Thử tưởng tượng xem, nếu mình dấn thân vào lĩnh vực Smart Home, kết nối tất cả thiết bị ở trong nhà thì nên bắt đầu như nào nhỉ? À đúng rồi, trước hết phải có 1 cái remote dùng để điều khiển. Remote này có thể điều khiển bóng đèn tắt mở nên nó sẽ có 2 cái nút, 1 nút để tắt, 1 nút để mở.
Nhưng trong nhà thì có nhiều loại bóng đèn lắm, phòng khách có đèn chùm, nhà vệ sinh có đèn huỳnh quang, phòng ăn có đèn sợi tóc... cả tá đèn thì lập trình thế quái nào được đây.
A, đúng rồi. Học strategy pattern rồi, áp dụng vào thôi! Đơn giản quá đi mà.
Mình sẽ tạo 1 interface là ILight, interface này có 2 chức năng là on và off. Từ đó có thể tạo bao nhiêu hiện thực của nó tùy thích. Bây giờ rất đơn giản, chỉ cần ghán 1 nút của remote chạy hàm on, 1 nút chạy hàm off là được. Muốn điều khiển bóng đèn nào thì chỉ cần set hiện thực của nó vào remote là được. Đơn giản.
Nhưng, ngoài bóng đèn ra còn có nhiều cái khác nữa mà. Ví dụ muốn điều khiển cả tivi nữa. Bấm 1 nút là chuyển kênh, bấm 1 nút là tăng âm lượng. Hừm, ok. Mình sẽ áp dụng strategy pattern tương tự cho tivi để phù hợp với các hãng tivi khác nhau như samsung, sony, lg.... Sau đó gia công thêm vài nút lên cái remote, rồi cài đặt cho những nút đó là xong.
Nhưng trong nhà lại có thêm máy giặt, tủ lạnh, quạt điện.... với biết bao nhiêu là chức năng cần thực hiện. Mà mỗi vật như thế thì có biết bao nhiêu là loại khác nhau. Giờ làm sao đây nhỉ? Nếu cứ thiết kế theo kiểu trên chắc người ta cười vào mặt công ty mình mất.
Và đây chính là lúc, chúng ta nên áp dụng Command Pattern.
Command Pattern: đóng gói mỗi yêu cầu thành những đối tượng để bạn có thể tương tác với những đối tượng bằng những yêu cầu khác nhau. Thể loại Pattern này cũng cho phép ta thực hiện được cái hành động undo nữa
Okie! như thường lệ, ví dụ sẽ làm sáng tỏ định nghĩa.
Với ví dụ smart home ở trên, thay vì ta gộp từng loại thiết bị theo strategy pattern, chúng ta sẽ phân chia mỗi yêu cầu thành từng đối tượng. Có nghĩa rằng, với yêu cầu bật đèn - nó sẽ là 1 đối tượng. Yêu cầu tắt đèn - nó cũng sẽ là 1 đối tượng. Yêu cầu chuyển kênh, tăng âm lượng, giặt áo quần, sấy áo quần, bật quạt, tắt quạt.... - mỗi yêu cầu như thế sẽ là 1 đối tượng.
Và bây giờ, những nút bấm của remote không cần phải gán từng chức năng riêng lẽ như on off nữa, mà nó sẽ được gắn vào những đối tượng đã nêu trên. Ví dụ, nếu gọi cái remote là invoker, các thiết bị của chúng ta là receiver, chúng ta sẽ có mô hình Command pattern sau đây. Quá trình hoạt động sẽ như sau. Đầu tiên ta sẽ set nút bấm trên remote sẽ làm command nào. Sau đó, khi ta bấm nút, class command sẽ trigger hoạt động execute để gọi tới action của thiết bị. Vậy thôi.
Để rõ hơn, ta đi vào vài dòng code nhé. Đầu tiên là ta có các thiết bị.
public interface Light { public void turnOn(); public void turnOff(); } public interface Tivi{ public void nextChannel(); } public class PhilipLight implements Light{ public void turnOn() { // bat bong den } public void turnOff() { // tat bong den } } public class SamsungTivi implements Tivi{ public void nextChannel() { // chuyen kenh } }Tiếp đến ta tạo interface cho ICommand và các hiện thực của nó.
public interface ICommand { public void execute(); public void undo(); } public class TurnLightOnCommand implements ICommand { private Light lightl public void TurnLightOnCommand (Light light) { this.light = light; } public void execute() { this.light.turnOn(); } public void undo() { // redo turn on. } } public class SwitchChannelCommand implements ICommand { private Tivi tivi public void TurnLightOnCommand (Tivi tivi) { this.tivi = tivi; } public void execute() { this.tivi.nextChannel(); } public void undo() { // redo next channel. } }Tiếp đến bạn tạo ra invoker cho cái điều khiển.
public class Invoker { private ICommand command; public void setCommand(ICommand command) { this.command = command; } public void press() { this.command.excute(); } }Bây giờ giả sử bạn muốn nút bấm trên remote của bạn dùng để bật bóng đèn Philip ngoài phòng khách chẳng hạn. Bạn chỉ cần:
ICommand command = new TurnLightOnCommand(new PhilipLight()); Invoker invoker = new Invoker(); invoker.setCommand(command);Và khi bạn ấn nút thì chạy dòng code sau.
invoker.press();Vậy là xong. Đó chính là Command Pattern. Còn về phần mà undo tác vụ ấy. Chúng ta hãy liên tưởng tới các phần mềm kiểu như photoshop, khi chúng ta thực hiện thao tác nào đó, thì hãy xem mỗi thao tác đó là 1 command. Ví dụ ta vẽ 1 đường thẳng, chính là 1 command, chúng ta đổi màu cũng là 1 command.... Để tổ chức các command đó thì chúng ta có thể dùng stack để lưu, và khi ta ctrl + Z, thì chỉ cần bóc cái command trong stack ra và chạy hàm undo là được. Rất đơn giản.
0 nhận xét:
Đăng nhận xét