Mẫu thiết kế Command

Behavioral Design Pattern

Mô tả chung

Command là một mẫu thiết kế thuộc nhóm Behavioral Design Pattern (Mẫu thiết kế được sử dụng để giải quyết các vấn đề phổ biến trong hành vi giao tiếp giữa các đối tượng).

Command được sử dụng để quản lý các thuật toán, các mối quan hệ và trách nhiệm giữa các đối tượng. Cuốn sách về Design Pattern của “Gang of Four” nói về mẫu thiết kế này như sau:

Đóng gói một yêu cầu như một đối tượng, do đó cho phép bạn tham số hóa các client với các yêu cầu, hàng đợi hoặc yêu cầu log khác nhau và hỗ trợ khôi phục các hành động (undoable).

Khi nào nên dùng?

  • Cần biết lịch sử của các yêu cầu (request)
  • Cần chức năng callback
  • Yêu cầu cần phải được xử lý vào các thời điểm khác nhau hoặc theo thứ tự khác nhau
  • Invoker (đối tượng triệu gọi) cần được tách biệt khỏi Receiver (đối tượng nhận và xử lý yêu cầu).

Ghi chú: Nói một cách dễ hiểu, callback tức là ta truyền Hàm A vào Hàm B. Tới một thời điểm nào đó, Hàm A sẽ được Hàm B gọi lại.

Các thành phần Cấu trúc

Command định nghĩa một interface cho tất cả các mệnh lệnh, cung cấp phương thức execute() yêu cầu Receiver (cầu đối tượng nhận lệnh) thực hiện một hành động. Receiver biết cách thực hiện yêu cầu đó như thế nào. Invoker nắm giữ mệnh lệnh và có thể yêu cầu một Command thực thi yêu cầu bằng cách gọi phương thức execute().

Mẫu thiết kế này luôn có 3 lớp gắn liền với nhau, đó là ClientInvoker và Receiver:

  • Client tạo đối tượng Command và cung cấp các thông tin cần thiết để gọi các yêu cầu vào một thời điểm nào đó.
  • Invoker quyết định lúc nào các yêu cầu này được gọi.
  • Receiver chứa các yêu cầu cần được thực hiện.

Trong đó:

  • Command: Định nghĩa một interface để thực hiện một hành động (Execute). Là đối tượng lưu giữ Request và State của một đối tượng tại một thời điểm.
  • ConcreteCommand: Cài đặt Excute bằng cách khai báo các hoạt động tương ứng trên Receiver.
  • Client: tạo ra một đối tượng ConcreteCommand và thiết lập Receiver của nó.
  • Invoker: Là nơi lưu trữ và phát sinh mỗi Request dưới dạng đối tượng Command. Quyết định khi nào thực hiện nó.
  • Receiver:  Là đối tượng thực hiện lệnh trên mỗi yêu cầu.

Triển khai

Bước 1: Định nghĩa lớp Light (bóng đèn) có hai phương thức switchOn (bật) và switchOff (tắt). Trong mô hình của mẫu Command, Light là lớp nhận và thực thi yêu cầu (Receiver).

 public class Light {
   private boolean on;

   public void switchOn() {
       on = true;
       System.out.println(“on”);
   }

   public void switchOff() {
       on = false;
       System.out.println(“off”);
   }
}

Bước 2: Tạo interface tên là Command khai báo một phương thức execute(), phương thức sẽ thực thi hành động cụ thể được định nghĩa ở các lớp kế thừa.

 public interface Command {
   void execute();
}

Bước 3: Tạo hai lớp cụ thể kế thừa Command là: LightOnCommand (thực hiện hành động bật đèn) và LightOffCommand (thực hiện hành động tắt đèn) (trong mô hình thiết kế trên hai lớp này là ConcreteCommand)

public class LightOnCommand implements Command{
   //reference to the light
   Light light;

   public LightOnCommand(Light light) {
       this.light = light;
   }

   public void execute() {
       light.switchOn();
   }
}


public class LightOffCommand implements Command {
   //reference to the light
   Light light;

   public LightOffCommand(Light light) {
       this.light = light;
   }

   public void execute() {
       light.switchOff();
   }
}

Bước 4: Đưa các Command này vào trong một bộ điều khiển, lớp RemoteControl (đóng vai trò Invoker trong mô hình thiết kế). Lớp này chứa một đối tượng Command để thực thi các mệnh lệnh.

public class RemoteControl {
   private Command command;

   public void setCommand(Command command) {
       this.command = command;
   }

   public void pressButton() {
       command.execute();
   }
}

Bước 5: Viết lớp Client để sử dụng bộ điều khiển (RemoteControl).

public class Client {
public static void main(String[] args) {

//create a remote control
RemoteControl control = new RemoteControl();
//create a light

Light light = new Light();
//Create 2 command

Command lightsOn = new LightOnCommand(light);
Command lightsOff = new LightOffCommand(light);
//switch on
control.setCommand(lightsOn);
control.pressButton();
//switch off
control.setCommand(lightsOff);
control.pressButton();
}
}

Như vậy, ta có thể truyền bất cứ Command nào vào RemoteControl để yêu cầu thực hiện. Vậy là các yêu cầu đã được đóng gói vào trong một đối tượng.

Tham khảo:

https://dzone.com | http://www.opencodez.com


Hãy tham gia nhóm Học lập trình để thảo luận thêm về các vấn đề cùng quan tâm.

Leave a Reply

Your email address will not be published. Required fields are marked *