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 Behavior Pattern Hướng dẫn Java Design Pattern – Command

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

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

Đôi khi chúng ta cần gửi các yêu cầu cho các đối tượng mà không biết bất cứ điều gì về hoạt động được yêu cầu hoặc người nhận yêu cầu. Chẳng hạn chúng có một ứng dụng văn bản, khi click lên button undo/ redo, save, … yêu cầu sẽ được chuyển đến hệ thống xử lý, chúng ta sẽ không thể biết được đối tượng nào sẽ nhận xử lý, cách nó thực hiện như thế nào. Command Pattern là một Pattern được thiết kế cho những ứng dụng như vậy.

Nội dung

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

Command Pattern là gì?

Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.

Command Pattern là một trong những Pattern thuộc nhóm hành vi (Behavior Pattern). Nó cho phép chuyển yêu cầu thành đối tượng độc lập, có thể được sử dụng để tham số hóa các đối tượng với các yêu cầu khác nhau như log, queue (undo/redo), transtraction.

Nói cho dễ hiểu, Command Pattern cho phép tất cả những Request gửi đến object được lưu trữ trong chính object đó dưới dạng một object Command. Khái niệm Command Object giống như một class trung gian được tạo ra để lưu trữ các câu lệnh và trạng thái của object tại một thời điểm nào đó.

Command dịch ra nghĩa là ra lệnh. Commander nghĩa là chỉ huy, người này không làm mà chỉ ra lệnh cho người khác làm. Như vậy, phải có người nhận lệnh và thi hành lệnh. Người ra lệnh cần cung cấp một class đóng gói những mệnh lệnh. Người nhận mệnh lệnh cần phân biệt những interface nào để thực hiện đúng mệnh lệnh.

Command Pattern còn được biết đến như là Action hoặc Transaction.

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

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

  • Command : là một interface hoặc abstract class, chứa một phương thức trừu tượng thực thi (execute) một hành động (operation). Request sẽ được đóng gói dưới dạng Command.
  • ConcreteCommand : là các implementation của Command. Định nghĩa một sự gắn kết giữa một đối tượng Receiver và một hành động. Thực thi execute() bằng việc gọi operation đang hoãn trên Receiver. Mỗi một ConcreteCommand sẽ phục vụ cho một case request riêng.
  • Client : tiếp nhận request từ phía người dùng, đóng gói request thành ConcreteCommand thích hợp và thiết lập receiver của nó.
  • Invoker : tiếp nhận ConcreteCommand từ Client và gọi execute() của ConcreteCommand để thực thi request.
  • Receiver : đây là thành phần thực sự xử lý business logic cho case request. Trong phương execute() của ConcreteCommand chúng ta sẽ gọi method thích hợp trong Receiver.

Như vậy, Client và Invoker sẽ thực hiện việc tiếp nhận request. Còn việc thực thi request sẽ do Command, ConcreteCommand và Receiver đảm nhận.

Ví dụ Command Pattern trong ứng dụng mở tài khoản ngân hàng

Một hệ thống ngân hàng cung cấp ứng dụng cho khách hàng (client) có thể mở (open) hoặc đóng (close) tài khoản trực tuyến. Hệ thống này được thiết kế theo dạng module, mỗi module sẽ thực hiện một nhiệm vụ riêng của nó, chẳng hạn mở tài khoản (OpenAccount), đóng tài khoản (CloseAccount). Do hệ thống không biết mỗi module sẽ làm gì, nên khi có yêu cầu client (chẳng hạn clickOpenAccount, clickCloseAccount), nó sẽ đóng gói yêu cầu này và gọi module xử lý.

Ứng dụng của chúng ta bao gồm các lớp xử lý sau:

  • Account : là một request class.
  • Command : là một interface của Command Pattern, cung cấp phương thức execute().
  • OpenAccount, CloseAccount : là các ConcreteCommand, cài đặt các phương thức của Command, sẽ thực hiện các xử lý thực tế.
  • BankApp : là một class, hoạt động như Invoker, gọi execute() của ConcreteCommand để thực thi request.
  • Client : tiếp nhận request từ phía người dùng, đóng gói request thành ConcreteCommand thích hợp và gọi thực thi các Command.

Account.java


package com.gpcoder.patterns.behavioral.command.bank;

public class Account {
	private String name;

	public Account(String name) {
		this.name = name;
	}

	public void open() {
		System.out.println("Account [" + name + "] Opened\n");
	}

	public void close() {
		System.out.println("Account [" + name + "] Closed\n");
	}
}

Command.java


package com.gpcoder.patterns.behavioral.command.bank;

public interface Command {

	void execute();
}

OpenAccount.java


package com.gpcoder.patterns.behavioral.command.bank;

public class OpenAccount implements Command {

	private Account account;

	public OpenAccount(Account account) {
		this.account = account;
	}

	@Override
	public void execute() {
		account.open();
	}
}

CloseAccount.java


package com.gpcoder.patterns.behavioral.command.bank;

public class CloseAccount implements Command {

	private Account account;

	public CloseAccount(Account account) {
		this.account = account;
	}

	@Override
	public void execute() {
		account.close();
	}
}

BankApp.java


package com.gpcoder.patterns.behavioral.command.bank;

public class BankApp {

	private Command openAccount;
	private Command closeAccount;

	public BankApp(Command openAccount, Command closeAccount) {
		this.openAccount = openAccount;
		this.closeAccount = closeAccount;
	}

	public void clickOpenAccount() {
		System.out.println("User click open an account");
		openAccount.execute();
	}

	public void clickCloseAccount() {
		System.out.println("User click close an account");
		closeAccount.execute();
	}
}

Client.java


package com.gpcoder.patterns.behavioral.command.bank;

public class Client {

	public static void main(String[] args) {
		Account account = new Account("gpcoder");

		Command open = new OpenAccount(account);
		Command close = new CloseAccount(account);
		BankApp bankApp = new BankApp(open, close);

		bankApp.clickOpenAccount();
		bankApp.clickCloseAccount();
	}
}

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


User click open an account
Account [gpcoder] Opened

User click close an account
Account [gpcoder] Closed

Một cách implement khác general hơn:
package com.gpcoder.patterns.behavioral.command.bank;

public class BankApp {

	public void click(Command command) {
		System.out.println("User click " + command.getSimpleName());
		command.execute();
	}
}

public class Client {

	public static void main(String[] args) {
		Account account = new Account("gpcoder");

		Command open = new OpenAccount(account);
		Command close = new CloseAccount(account);

		BankApp bankApp = new BankApp();
		bankApp.click(open);
		bankApp.click(close);
	}
}

Ví dụ Command Pattern trong ứng dụng quản lý văn bản

Ứng dụng văn bản cần một chức năng để thêm hoặc lưu trữ những hành động undo hay redo.

Lớp Document chỉ cung cấp phương thức ghi thêm một dòng văn bản mới hoặc xóa một dòng văn bản đã ghi trước đó.

Chúng ta sẽ xây dựng một interface Command để cung cấp hành động undo/ redo. Để sử dụng Command chúng ta cần một DocumentInvoker, lớp này sử dụng tính năng của Stack để lưu lại lịch sử những lần thêm mới và những lần xóa, tương ứng với undoCommands và redoCommands.

Stack (ngăn xếp) là một cấu trúc dữ liệu trừu tượng hoạt động theo nguyên lý “vào sau ra trước” (Last In First Out (LIFO).

Một số phương thức của Stack:

  • push() : thêm phần tử trên đỉnh của Stack.
  • pop() : xóa phần tử trên đỉnh của Stack và trả về phần tử bị xóa.
  • peek() : lấy phần tử trên đỉnh của Stack, nhưng không xóa nó khỏi Stack.
  • clear() : xóa tất cả các phần tử trong Stack.
  • isEmpty() : kiểm tra Stack có chứa phần tử nào không.

Document.java


package com.gpcoder.patterns.behavioral.command.document;

import java.util.Stack;

public class Document {
	private Stack<String> lines = new Stack<>();

	public void write(String text) {
		lines.push(text);
	}

	public void eraseLast() {
		if (!lines.isEmpty()) {
			lines.pop();
		}
	}

	public void readDocument() {
		for (String line : lines) {
			System.out.println(line);
		}
	}
}

Command.java


package com.gpcoder.patterns.behavioral.command.document;

public interface Command {
	void undo();

	void redo();
}

DocumentEditorCommand.java


package com.gpcoder.patterns.behavioral.command.document;

public class DocumentEditorCommand implements Command {

	private Document document;
	private String text;

	public DocumentEditorCommand(Document document, String text) {
		this.document = document;
		this.text = text;
		this.document.write(text);
	}

	public void undo() {
		document.eraseLast();
	}

	public void redo() {
		document.write(text);
	}
}

DocumentInvoker.java


package com.gpcoder.patterns.behavioral.command.document;

import java.util.Stack;

public class DocumentInvoker {
	private Stack<Command> undoCommands = new Stack<>();
	private Stack<Command> redoCommands = new Stack<>();
	private Document document = new Document();

	public void undo() {
		if (!undoCommands.isEmpty()) {
			Command cmd = undoCommands.pop();
			cmd.undo();
			redoCommands.push(cmd);
		} else {
			System.out.println("Nothing to undo");
		}
	}

	public void redo() {
		if (!redoCommands.isEmpty()) {
			Command cmd = redoCommands.pop();
			cmd.redo();
			undoCommands.push(cmd);
		} else {
			System.out.println("Nothing to redo");
		}
	}

	public void write(String text) {
		Command cmd = new DocumentEditorCommand(document, text);
		undoCommands.push(cmd);
		redoCommands.clear();
	}

	public void read() {
		document.readDocument();
	}
}

Client.java


package com.gpcoder.patterns.behavioral.command.document;

public class Client {

	public static void main(String[] args) {
		DocumentInvoker instance = new DocumentInvoker();
		instance.write("The 1st text. ");
		instance.undo();
		instance.read(); // EMPTY

		instance.redo();
		instance.read(); // The 1st text.

		instance.write("The 2nd text. ");
		instance.write("The 3rd text. ");
		instance.read(); // The 1st text. The 2nd text. The 3rd text.
		instance.undo(); // The 1st text. The 2nd text.
		instance.undo(); // The 1st text.
		instance.undo(); // EMPTY
		instance.undo(); // Nothing to undo
	}
}

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


The 1st text.
The 1st text.
The 2nd text.
The 3rd text.
Nothing to undo

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

  • Dễ dàng thêm các Command mới trong hệ thống mà không cần thay đổi trong các lớp hiện có. Đảm bảo Open/Closed Principle.
  • Tách đối tượng gọi operation từ đối tượng thực sự thực hiện operation. Giảm kết nối giữa Invoker và Receiver.
  • Cho phép tham số hóa các yêu cầu khác nhau bằng một hành động để thực hiện.
  • Cho phép lưu các yêu cầu trong hàng đợi.
  • Đóng gói một yêu cầu trong một đối tượng. Dễ dàng chuyển dữ liệu dưới dạng đối tượng giữa các thành phần hệ thống.

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

  • Khi cần tham số hóa các đối tượng theo một hành động thực hiện.
  • Khi cần tạo và thực thi các yêu cầu vào các thời điểm khác nhau.
  • Khi cần hỗ trợ tính năng undo, log , callback hoặc transaction.

Tài liệu tham khảo:

  • https://sourcemaking.com/design_patterns/command
  • https://refactoring.guru/design-patterns/command
  • https://www.javatpoint.com/command-pattern
  • https://www.tutorialspoint.com/design_pattern/command_pattern.htm
  • https://quachson.wordpress.com/2011/04/22/design-pattern-command/
  • Design Patterns: Elements of Reusable Object-Oriented Software – GOF
4.7
15
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 – Chain of Responsibility
Hướng dẫn Java Design Pattern – Interpreter

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

  • Hướng dẫn Java Design Pattern – Factory Method (12/09/2018)
  • Hướng dẫn Java Design Pattern – Mediator (20/12/2018)
  • Giới thiệu Google Guice – Aspect Oriented Programming (AOP) (14/02/2019)
  • Hướng dẫn Java Design Pattern – Proxy (30/11/2018)
  • Hướng dẫn Java Design Pattern – Singleton (08/09/2018)

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