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".
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).
Lư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à Client, Invoker
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)
Cài đặt lớp LightOnCommand
public class LightOnCommand implements Command{
//reference to the light Light light;
public LightOnCommand(Light light) {
this.light = light;
}
public void execute() {
light.switchOn();
}
}
Cài đặt lớp LightOffCommand
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.
Đăng nhận xét