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 – Chain of Responsibility

Hướng dẫn Java Design Pattern – Chain of Responsibility

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

Trong các viết trước chúng ta đã cùng tìm hiểu về các Design Pattern thuộc nhóm cấu trúc (Structuaral Pattern). Trong bài viết hôm nay chúng ta sẽ cùng tìm hiểu một Pattern thuộc nhóm hành vi (Behavior Pattern) là Chain of Responsibility.

Toàn bộ các  mẫu hành vi (Behavior Pattern) xoay quanh nguyên tắc “thành phần đối tượng (composition) hơn là thừa kế (inheritance)”. Nguyên tắc này nói rằng, thay vì mở rộng từ một lớp hiện có, thiết kế lớp của bạn để tham chiếu một lớp hiện có mà bạn muốn sử dụng. Trong Java, nó được thực hiện bằng cách khai báo một biến tham chiếu đối tượng của lớp hiện có. Sau đó, bằng cách khởi tạo đối tượng thông qua hàm tạo (constructor) hoặc phương thức (setter), và cuối cùng sử dụng đối tượng được tham chiếu.

Nội dung

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

Chain of Responsibility Pattern là gì?

Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along with the chain until an object handles it.

Chain of Responsibility (COR) là một trong những Pattern thuộc nhóm hành vi (Behavior Pattern).

Chain of Responsiblity cho phép một đối tượng gửi một yêu cầu nhưng không biết đối tượng nào sẽ nhận và xử lý nó. Điều này được thực hiện bằng cách kết nối các đối tượng nhận yêu cầu thành một chuỗi (chain) và gửi yêu cầu theo chuỗi đó cho đến khi có một đối tượng xử lý nó.

Chain of Responsibility Pattern hoạt động như một danh sách liên kết (Linked list) với việc đệ quy duyệt qua các phần tử (recursive traversal).

Cài đặt Chain of Responsibility Pattern như thế nào?

Các thành phần tham gia mẫu Chain of Responsibility:

  • Handler : định nghĩa 1 interface để xử lý các yêu cầu. Gán giá trị cho đối tượng successor (không bắt buộc).
  • ConcreteHandler : xử lý yêu cầu. Có thể truy cập đối tượng successor (thuộc class Handler). Nếu đối tượng ConcreateHandler không thể xử lý được yêu cầu, nó sẽ gởi lời yêu cầu cho successor của nó.
  • Client : tạo ra các yêu cầu và yêu cầu đó sẽ được gửi đến các đối tượng tiếp nhận.

Client gửi một yêu cầu để được xử lý gửi nó đến chuỗi (chain) các trình xử lý (handers), đó là các lớp mở rộng lớp Handler. Mỗi Hanlder trong chuỗi lần lượt cố gắng xử lý yêu cầu nhận được từ Client. Nếu trình xử lý đầu tiên (ConcreteHandler) có thể xử lý nó, thì yêu cầu sẽ được xử lý. Nếu không được xử lý thì sẽ gửi đến trình xử lý tiếp theo trong chuỗi (ConcreteHandler + 1).

Các bạn có thể tham khảo cách implement về Chain of Responsibility trong các thư viện của Java như:

  • java.util.logging.Logger#log()
  • javax.servlet.Filter#doFilter()

Ví dụ Chain of Responsibility Pattern với ứng dụng Logger

Trong ví dụ này, chúng ta sẽ tự xây dựng hệ thống Logger cho riêng mình như sau:

  • Logger: là một abstract class Handler, cho phép thực hiện một chain logger dựa vào giá trị LogLevel ứng với từng Handler. Nếu mức độ lỗi (severity) lớn hơn hoặc bằng với LogLevel mà nó có thể handle thì sẽ thực hiện writeMessage(), đồng thời gọi Hanlder kế tiếp nếu có.
  • ConsoleLogger, FileLogger, EmailLogger: đây là các ConcreteHandler, nó xác định LogLevel mà nó có thể xử lý, và cài đặt phương thức writeMessage() cho riêng nó.
  • Client : sử dụng Logger để ghi log.
  • LogLevel : là một enum (constant), dùng để xác định các mức độ ghi log.
  • AppLogger: là một lớp tiện ích, tạo chuỗi Handler để xử lý ghi log.

LogLevel.java


package com.gpcoder.patterns.behavioral.cor.logger;

public enum LogLevel {
	NONE(0), INFO(1), DEBUG(2), WARNING(4), ERROR(8), FATAL(16), ALL(32);

	private int level;

	private LogLevel(int level) {
		this.level = level;
	}

	public int getLevel() {
		return level;
	}
}

Logger.java


package com.gpcoder.patterns.behavioral.cor.logger;

public abstract class Logger {

	protected LogLevel logLevel;

	protected Logger nextlogger; // The next Handler in the chain

	public Logger(LogLevel logLevel) {
		this.logLevel = logLevel;
	}

	// Set the next logger to make a list/chain of Handlers.
	public Logger setNext(Logger nextlogger) {
		this.nextlogger = nextlogger;
		return nextlogger;
	}

	public void log(LogLevel severity, String msg) {
		if (logLevel.getLevel() <= severity.getLevel()) {
			writeMessage(msg);
		}
		if (nextlogger != null) {
			nextlogger.log(severity, msg);
		}
	}

	protected abstract void writeMessage(String msg);
}

ConsoleLogger.java


package com.gpcoder.patterns.behavioral.cor.logger;

public class ConsoleLogger extends Logger {

	public ConsoleLogger(LogLevel logLevel) {
		super(logLevel);
	}

	@Override
	protected void writeMessage(String msg) {
		System.out.println("Console logger: " + msg);
	}
}

FileLogger.java


package com.gpcoder.patterns.behavioral.cor.logger;

public class FileLogger extends Logger {

	public FileLogger(LogLevel logLevel) {
		super(logLevel);
	}

	@Override
	protected void writeMessage(String msg) {
		System.out.println("File logger: " + msg);
	}
}

EmailLogger.java


package com.gpcoder.patterns.behavioral.cor.logger;

public class EmailLogger extends Logger {

	public EmailLogger(LogLevel logLevel) {
		super(logLevel);
	}

	@Override
	protected void writeMessage(String msg) {
		System.out.println("Email logger: " + msg);
	}
}

AppLogger.java


package com.gpcoder.patterns.behavioral.cor.logger;

public class AppLogger {

	public static Logger getLogger() {
		Logger consoleLogger = new ConsoleLogger(LogLevel.DEBUG);
		Logger fileLogger = consoleLogger.setNext(new FileLogger(LogLevel.ERROR));
		fileLogger.setNext(new EmailLogger(LogLevel.FATAL));
		return consoleLogger;
	}
}

Client.java


package com.gpcoder.patterns.behavioral.cor.logger;

/**
 * Chain of Responsibility Pattern Examle
 * 
 * @author gpcoder.com
 */
public class Client {

	public static void main(String[] args) {
		// Build the chain of responsibility
		Logger logger = AppLogger.getLogger();

		// Handled by ConsoleLogger since the console has a LogLevel of DEBUG
		logger.log(LogLevel.INFO, "Info message");
		logger.log(LogLevel.DEBUG, "Debug message");

		// Handled by ConsoleLogger and FileLogger
		logger.log(LogLevel.ERROR, "Error message");

		// Handled by ConsoleLogger, FileLogger, EmailLogger
		logger.log(LogLevel.FATAL, "Factal message");
	}
}

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


Console logger: Debug message
Console logger: Error message
File logger: Error message
Console logger: Factal message
File logger: Factal message
Email logger: Factal message

Ở ví dụ này, chain của chúng ta sẽ kết thúc khi tất cả các đối tượng trong chain có thể xử lý đã xử lý.

Ví dụ Chain of Responsibility Pattern với ứng dụng LeaveRequest

Một ví dụ khác là ứng dụng phê duyệt xin nghỉ phép. Nếu xin nghỉ <=3 ngày thì Supervisor có thể phê duyệt (approve). Nếu xin nghỉ <=5 ngày thì DeliveryManager có thể approve. Nếu xin nghỉ >5 ngày thì phải được approve bởi Director. Quy trình này có thể linh động tùy theo quy mô phát triển của công ty.

LeaveRequest.java


package com.gpcoder.patterns.behavioral.cor.leaverequest;

public class LeaveRequest {
	private int days;

	public LeaveRequest(int days) {
		this.days = days;
	}

	public int getDays() {
		return days;
	}
}

Approver.java


package com.gpcoder.patterns.behavioral.cor.leaverequest;

public abstract class Approver {

	protected Approver nextApprover;

	public void approveLeave(LeaveRequest request) {
		System.out.println("Checking permission for " + this.getClass().getSimpleName());
		if (this.canApprove(request.getDays())) {
			this.doApproving(request);
		} else if (nextApprover != null) {
			nextApprover.approveLeave(request);
		}
	}

	public void setNext(Approver approver) {
		this.nextApprover = approver;
	}

	protected abstract boolean canApprove(int numberOfDays);

	protected abstract void doApproving(LeaveRequest request);
}

Supervisor.java


package com.gpcoder.patterns.behavioral.cor.leaverequest;

public class Supervisor extends Approver {

	@Override
	protected boolean canApprove(int numberOfDays) {
		return numberOfDays <= 3;
	}

	@Override
	protected void doApproving(LeaveRequest request) {
		System.out.println("Leave request approved for " + request.getDays() + " days by Supervisor");
	}
}

DeliveryManager.java


package com.gpcoder.patterns.behavioral.cor.leaverequest;

public class DeliveryManager extends Approver {

	@Override
	protected boolean canApprove(int numberOfDays) {
		return numberOfDays <= 5;
	}

	@Override
	protected void doApproving(LeaveRequest request) {
		System.out.println("Leave request approved for " + request.getDays() + " days by Delivery Manager");
	}
}

Director.java


package com.gpcoder.patterns.behavioral.cor.leaverequest;

public class Director extends Approver {

	@Override
	protected boolean canApprove(int numberOfDays) {
		return numberOfDays > 5;
	}

	@Override
	protected void doApproving(LeaveRequest request) {
		System.out.println("Leave request approved for " + request.getDays() + " days by Director");
	}
}

LeaveRequestWorkFlow.java


package com.gpcoder.patterns.behavioral.cor.leaverequest;

public class LeaveRequestWorkFlow {

	public static Approver getApprover() {
		Approver supervisor = new Supervisor();
		Approver manager = new DeliveryManager();
		Approver director = new Director();

		supervisor.setNext(manager);
		manager.setNext(director);
		return supervisor;
	}
}

App.java


package com.gpcoder.patterns.behavioral.cor.leaverequest;

public class App {

	public static void main(String[] args) {
		LeaveRequestWorkFlow.getApprover().approveLeave(new LeaveRequest(2));
		System.out.println("---");
		LeaveRequestWorkFlow.getApprover().approveLeave(new LeaveRequest(5));
		System.out.println("---");
		LeaveRequestWorkFlow.getApprover().approveLeave(new LeaveRequest(7));
	}
}

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


Checking permission for Supervisor
Leave request approved for 2 days by Supervisor
---
Checking permission for Supervisor
Checking permission for DeliveryManager
Leave request approved for 5 days by Delivery Manager
---
Checking permission for Supervisor
Checking permission for DeliveryManager
Checking permission for Director
Leave request approved for 7 days by Director

Ở ví dụ này, chain của chúng ta sẽ kết thúc khi có một đối tượng có thể xử lý.

Lợi ích của Chain of Responsibility Pattern là gì?

  • Giảm kết nối (loose coupling): Thay vì một đối tượng có khả năng xử lý yêu cầu chứa tham chiếu đến tất cả các đối tượng khác, nó chỉ cần một tham chiếu đến đối tượng tiếp theo. Tránh sự liên kết trực tiếp giữa đối tượng gửi yêu cầu (sender) và các đối tượng nhận yêu cầu (receivers).
  • Tăng tính linh hoạt : đảm bảo Open/Closed Principle.
  • Phân chia trách nhiệm cho các đối tượng: đảm bảo Single Responsibility Principle.
  • Có khả năng thay đổi dây chuyền (chain) trong thời gian chạy.
  • Không đảm bảo có đối tượng xử lý yêu cầu.

Sử dụng Chain of Responsibility Pattern khi nào?

  • Có nhiều hơn một đối tượng có khả thực xử lý một yêu cầu trong khi đối tượng cụ thể nào xử lý yêu cầu đó lại phụ thuộc vào ngữ cảnh sử dụng.
  • Muốn gửi yêu cầu đến một trong số vài đối tượng nhưng không xác định đối tượng cụ thể nào sẽ xử lý yêu cầu đó.
  • Khi cần phải thực thi các trình xử lý theo một thứ tự nhất định..
  • Khi một tập hợp các đối tượng xử lý có thể thay đổi động: tập hợp các đối tượng có khả năng xử lý yêu cầu có thể không biết trước, có thể thêm bớt hay thay đổi thứ tự sau này.

Tài liệu tham khảo:

  • https://sourcemaking.com/design_patterns/chain_of_responsibility
  • https://refactoring.guru/design-patterns/chain-of-responsibility
  • https://www.javatpoint.com/chain-of-responsibility-pattern
  • https://www.tutorialspoint.com/design_pattern/chain_of_responsibility_pattern.htm
  • Design Patterns: Elements of Reusable Object-Oriented Software – GOF
5.0
30
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 – Proxy
Hướng dẫn Java Design Pattern – Command

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

  • Hướng dẫn Java Design Pattern – Mediator (20/12/2018)
  • Hướng dẫn Java Design Pattern – Memento (25/12/2018)
  • Hướng dẫn Java Design Pattern – Strategy (03/01/2019)
  • Hướng dẫn Java Design Pattern – Dependency Injection (28/01/2019)
  • Giới thiệu Google Guice – Binding (05/02/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 (98059 lượt xem)
  • Hướng dẫn Java Design Pattern – Singleton (97700 lượt xem)
  • Giới thiệu Design Patterns (87764 lượt xem)
  • Lập trình đa luồng trong Java (Java Multi-threading) (86435 lượt xem)
  • Giới thiệu về Stream API trong Java 8 (83839 lượt xem)

Nội dung bài viết

  • 1 Chain of Responsibility Pattern là gì?
  • 2 Cài đặt Chain of Responsibility Pattern như thế nào?
  • 3 Lợi ích của Chain of Responsibility Pattern là gì?
  • 4 Sử dụng Chain of Responsibility 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