GP Coder

Trang chia sẻ kiến thức lập trình Java

  • Java Core
    • Basic Java
    • OOP
    • Exception Handling
    • Multi-Thread
    • Java I/O
    • Networking
    • Reflection
    • Collection
    • Java 8
  • Design pattern
    • Creational Pattern
    • Structuaral Pattern
    • Behavior Pattern
  • Web Service
    • SOAP
    • REST
  • JPA
  • Java library
    • Report
    • Json
    • Unit Test
  • Message Queue
    • ActiveMQ
    • RabbitMQ
  • All
Trang chủ Design pattern Hướng dẫn Java Design Pattern – State

Hướng dẫn Java Design Pattern – State

Đăng vào 31/12/2018 . Được đăng bởi GP Coder . 26908 Lượt xem . Toàn màn hình

Trong các ứng dụng, một số đối tượng có thông tin về trạng thái. Hành vi của đối tượng phụ thuộc vào trạng thái của nó tại thời điểm thực thi (run-time) và các phương thức xử lý nghiệp vụ có thể thay đổi trạng thái buộc đối tượng có hành vi xử lý khác đi. Trong trường hợp như vậy, chúng ta có thể sử dụng State Pattern.

Nội dung

  • 1 State Pattern là gì?
  • 2 Cài đặt State Pattern như thế nào?
  • 3 Lợi ích của State Pattern là gì?
  • 4 Sử dụng State Pattern khi nào?

State Pattern là gì?

Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.

State Pattern là một trong những Pattern thuộc nhóm hành vi (Behavior Pattern). Nó cho phép một đối tượng thay đổi hành vi của nó khi trạng thái nội bộ của nó thay đổi. Đối tượng sẽ xuất hiện để thay đổi lớp của nó.

Cài đặt State Pattern như thế nào?

Các thành phần tham gia State Pattern:

  • Context : được sử dụng bởi Client. Client không truy cập trực tiếp đến State của đối tượng. Lớp Context này chứa thông tin của ConcreteState object, cho hành vi nào tương ứng với trạng thái nào hiện đang được thực hiện.
  • State : là một interface hoặc abstract class xác định các đặc tính cơ bản của tất cả các đối tượng ConcreteState. Chúng sẽ được sử dụng bởi đối tượng Context để truy cập chức năng có thể thay đổi.
  • ConcreteState : cài đặt các phương thức của State. Mỗi ConcreteState có thể thực hiện logic và hành vi của riêng nó tùy thuộc vào Context.

Một vài điểm cần ghi nhớ khi áp dụng pattern này:

  • Một đối tượng nên thay đổi hành vi của nó khi trạng thái bên trong của nó thay đổi.
  • Mỗi State nên được xác định độc lập.
  • Thêm các trạng thái mới sẽ không làm ảnh hưởng đến các trạng thái hoặc chức năng khác.

Ví dụ State Pattern

Giả sử chúng ta cần xây dựng một ứng dụng quản lý Document. Một Document có thể bao gồm các trạng thái: tạo mới (New), trình phê duyệt (Submitted), phê duyệt (Approved) và từ chối (Rejected).

Với yêu cầu trên, chương trình của chúng ta như sau:


package com.gpcoder.patterns.behavioral.state.document.bad;

enum DocumentState {
	NEW, SUBMITTED, APPROVED, REJECTED
}

class DocumentService {
	private DocumentState state;

	public void setState(DocumentState state) {
		this.state = state;
	}

	public void handleRequest() {
		switch (state) {
		case NEW:
			System.out.println("Create a new document");
			break;
		case SUBMITTED:
			System.out.println("Submitted");
			break;
		case APPROVED:
			System.out.println("Approved");
			break;
		case REJECTED:
			System.out.println("Rejected");
			break;

		default:
			break;
		}
	}
}

public class DocumentApp {

	public static void main(String[] args) {
		DocumentService service = new DocumentService();

		service.setState(DocumentState.NEW);
		service.handleRequest();

		service.setState(DocumentState.SUBMITTED);
		service.handleRequest();

		service.setState(DocumentState.APPROVED);
		service.handleRequest();
	}
}

Output của chương trình:


Create a new document
Submitted
Approved

Như bạn thấy chương trình trên chạy ok, không vấn đề gì. Nhưng bây giờ chúng ta muốn thêm một trạng thái mới như lưu nháp (Save Draft). Đơn giản chúng ta chỉ cần thêm vào enum một giá trị mới và thêm điều kiện xử lý trong switch-case. Tuy nhiên, nếu làm như vậy thì chúng ta đã vi phạm nguyên tắc Open/ Close. Mỗi khi có thêm một trạng thái mới chúng ta phải sửa nhiều nơi, code trong phương thức handleRequest() ngày càng nhiều và cần phải test lại toàn bộ app.

Bây giờ chúng ta hãy áp dụng State Pattern cho chương trình trên:

  • Đầu tiên chúng ta sẽ tạo 1 base inteface để nhận yêu cầu xử lý. Lớp này gọi là State.
  • Tiếp theo, ứng với mỗi giá trị trong enum, chúng ta sẽ tạo một class mới và implement các phương thức của State.
  • Cuối cùng, chúng ta tạo một class Context. Class này chứa thông tin State hiện tại và nhận yêu cầu xử lý trực tiếp từ Client.

State.java


package com.gpcoder.patterns.behavioral.state.document.improve;

public interface State {
	
	void handleRequest();
}

NewState.java


package com.gpcoder.patterns.behavioral.state.document.improve;

public class NewState implements State {

	@Override
	public void handleRequest() {
		System.out.println("Create a new document");
	}
}

SubmittedState.java


package com.gpcoder.patterns.behavioral.state.document.improve;

public class SubmittedState implements State {

	@Override
	public void handleRequest() {
		System.out.println("Submitted");
	}
}

ApprovedState.java


package com.gpcoder.patterns.behavioral.state.document.improve;

public class ApprovedState implements State {

	@Override
	public void handleRequest() {
		System.out.println("Approved");
	}
}

RejectedState.java


package com.gpcoder.patterns.behavioral.state.document.improve;

public class RejectedState implements State {

	@Override
	public void handleRequest() {
		System.out.println("Rejected");
	}
}

DocumentContext.java


package com.gpcoder.patterns.behavioral.state.document.improve;

public class DocumentContext {

	private State state;

	public void setState(State state) {
		this.state = state;
	}

	public void applyState() {
		this.state.handleRequest();
	}
}

StatePatternExample.java


package com.gpcoder.patterns.behavioral.state.document.improve;

public class StatePatternExample {

	public static void main(String[] args) {
		DocumentContext context = new DocumentContext();

		context.setState(new NewState());
		context.applyState();

		context.setState(new SubmittedState());
		context.applyState();

		context.setState(new ApprovedState());
		context.applyState();
	}
}

Output của chương trình:


Create a new document
Submitted
Approved

Như bạn thấy, kết quả cũng không đổi. Tuy nhiên, chúng ta rất dễ dàng mở rộng. Nếu muốn thêm một trạng thái mới như lưu tạm (Save Draft), đơn giản tạo một class mới implements từ State mà không làm ảnh hưởng đến các State khác và Context.

Lợi ích của State Pattern là gì?

Lợi ích:

  • Đảm bảo nguyên tắc Single responsibility principle (SRP) : tách biệt mỗi State tương ứng với 1 class riêng biệt.
  • Đảm bảo nguyên tắc Open/Closed Principle (OCP) : chúng ta có thể thêm một State mới mà không ảnh hưởng đến State khác hay Context hiện có.
  • Giữ hành vi cụ thể tương ứng với trạng thái.
  • Giúp chuyển trạng thái một cách rõ ràng.

Sử dụng State Pattern khi nào?

  • Khi hành vi của đối tượng phụ thuộc vào trạng thái của nó và nó phải có khả năng thay đổi hành vi của nó lúc run-time theo trạng thái mới.
  • Khi nhiều điều kiện phức tạp buộc đối tượng phụ thuộc vào trạng thái của nó.

Tài liệu tham khảo:

  • https://sourcemaking.com/design_patterns/state
  • https://refactoring.guru/design-patterns/state
  • https://www.javatpoint.com/state-pattern
  • https://www.tutorialspoint.com/design_pattern/state_pattern.htm
  • Design Patterns: Elements of Reusable Object-Oriented Software – GOF
  • Design Pattern for dummies
4.8
20
Nếu bạn thấy hay thì hãy chia sẻ bài viết cho mọi người nhé! Và Donate tác giả

Shares

Chuyên mục: Behavior Pattern, Design pattern Được gắn thẻ: Behavior Pattern, Design pattern

Hướng dẫn Java Design Pattern – Observer
Hướng dẫn Java Design Pattern – Strategy

Có thể bạn muốn xem:

  • Refactoring Design Pattern với tính năng mới trong Java 8 (26/09/2019)
  • Giới thiệu Aspect Oriented Programming (AOP) (09/02/2019)
  • Giới thiệu Google Guice – Injection, Scope (07/02/2019)
  • Giới thiệu Google Guice – Aspect Oriented Programming (AOP) (14/02/2019)
  • Hướng dẫn Java Design Pattern – Dependency Injection (28/01/2019)

Bình luận

bình luận

Tìm kiếm

Bài viết mới

  • Clean code 13/01/2024
  • Giới thiệu CloudAMQP – Một RabbitMQ server trên Cloud 02/10/2020
  • Kết nối RabbitMQ sử dụng Web STOMP Plugin 19/06/2020
  • Sử dụng publisher confirm trong RabbitMQ 16/06/2020
  • Sử dụng Dead Letter Exchange trong RabbitMQ 13/06/2020

Xem nhiều

  • Hướng dẫn Java Design Pattern – Factory Method (98055 lượt xem)
  • Hướng dẫn Java Design Pattern – Singleton (97695 lượt xem)
  • Giới thiệu Design Patterns (87756 lượt xem)
  • Lập trình đa luồng trong Java (Java Multi-threading) (86426 lượt xem)
  • Giới thiệu về Stream API trong Java 8 (83827 lượt xem)

Nội dung bài viết

  • 1 State Pattern là gì?
  • 2 Cài đặt State Pattern như thế nào?
  • 3 Lợi ích của State Pattern là gì?
  • 4 Sử dụng State Pattern khi nào?

Lưu trữ

Thẻ đánh dấu

Annotation Authentication Basic Java Behavior Pattern Collection Creational Design Pattern Cấu trúc điều khiển Database Dependency Injection Design pattern Eclipse Exception Executor Service Google Guice Gson Hibernate How to Interceptor IO Jackson Java 8 Java Core JDBC JDK Jersey JMS JPA json JUnit JWT Message Queue Mockito Multithreading OOP PowerMockito RabbitMQ Reflection Report REST SOAP Structuaral Pattern Swagger Thread Pool Unit Test Webservice

Liên kết

  • Clean Code
  • JavaTpoint
  • Refactoring Guru
  • Source Making
  • TutorialsPoint
  • W3Schools Online Web Tutorials

Giới thiệu

GP Coder là trang web cá nhân, được thành lập với mục đích lưu trữ, chia sẽ kiến thức đã học và làm việc của tôi. Các bài viết trên trang này chủ yếu về ngôn ngữ Java và các công nghệ có liên quan đến Java như: Spring, JSF, Web Services, Unit Test, Hibernate, SQL, ...
Hi vọng góp được chút ít công sức cho sự phát triển cộng đồng Coder Việt.

Donate tác giả

Tìm kiếm các bài viết của GP Coder với Google Search

Liên hệ

Các bạn có thể liên hệ với tôi thông qua:
  • Trang liên hệ
  • Linkedin: gpcoder
  • Email: contact@gpcoder.com
  • Skype: ptgiang56it

Follow me

Copyright 2025 © GP Coder · All Rights Reserved · Giới thiệu · Chính sách · Điều khoản · Liên hệ ·

Share

Blogger
Delicious
Digg
Email
Facebook
Facebook messenger
Flipboard
Google
Hacker News
Line
LinkedIn
Mastodon
Mix
Odnoklassniki
PDF
Pinterest
Pocket
Print
Reddit
Renren
Short link
SMS
Skype
Telegram
Tumblr
Twitter
VKontakte
wechat
Weibo
WhatsApp
X
Xing
Yahoo! Mail

Copy short link

Copy link