Tìm hiểu Strategy Pattern
Tìm hiểu về Strategy pattern. _Bài viết được tham khảo từ cuốn Design pattern for dummies_ **1. Giới thiệu về design pattern** Design Pattern là một kỹ thuật trong lập trình hướng đối tượng, nó khá quan trọng và mọi lập trình viên muốn giỏi đều phải biết. Được sử dụng thường xuyên trong ...
Tìm hiểu về Strategy pattern.
_Bài viết được tham khảo từ cuốn Design pattern for dummies_
**1. Giới thiệu về design pattern**
Design Pattern là một kỹ thuật trong lập trình hướng đối tượng, nó khá quan trọng và mọi lập trình viên muốn giỏi đều phải biết. Được sử dụng thường xuyên trong các ngôn ngữ OOP. Nó sẽ cung cấp cho bạn các "mẫu thiết kế", giải pháp để giải quyết các vấn đề chung, thường gặp trong lập trình. Các vấn đề mà bạn gặp phải có thể bạn sẽ tự nghĩ ra cách giải quyết nhưng có thể nó chưa phải là tối ưu. Design Pattern giúp bạn giải quyết vấn đề một cách tối ưu nhất, cung cấp cho bạn các giải pháp trong lập trình OOP.
Trong Design Pattern có 3 nhóm bao gồm:
-
Creational Pattern (nhóm khởi tạo) gồm: Abstract Factory, Factory Method, Singleton, Builder, Prototype. Nó sẽ giúp bạn trong việt khởi tạo đối tượng, như bạn biết để khởi tạo bạn phải sử dụng từ khóa new, nhóm Creational Pattern sẽ sử dụng một số thủ thuật để khởi tạo đối tượng mà bạn sẽ không nhìn thấy từ khóa này.
-
Structural Pattern (nhóm cấu trúc) gồm: Adapter, Bridge, Composite, Decorator, Facade, Proxy và Flyweight.. Nó dùng để thiết lập, định nghĩa quan hệ giữa các đối tượng.
-
Behavioral Pattern gồm: Interpreter, Template Method, Chain of Responsibility, Command, Iterator, Mediator, Memento, Observer, State, Strategy và Visitor. Nhóm này dùng trong thực hiện các hành vi của đối tượng.
**2. Tìm hiểu strategy pattern**
Strategy pattern là gì? Strategy pattern (mẫu chiến lược): hiểu một cách đơn giản thì đây là mẫu thiết kế giúp bạn trừu tượng hóa những hành vi (behavior, method, function) của một đối tượng bằng cách đưa ra những cài đặt vào những lớp khác nhau.
Bài toán thực tế. Bạn nhận được một hợp đồng thiết kế ô tô. Có rất nhiều mẫu ô tô để bạn có thể làm. Bạn nghĩ ngay đến việc sử dụng OOP vào trong thiết kế ô tô của mình. Đầu tiên, bạn tạo ra 1 lớp cơ sở có tên là Vehicle với một phương thức có tên là go, phương thức này xuất hiện lên dòng chữ Now I’m driving.
abstract class Vehicle { public function go() { echo "Now I'm driving"; } }
Sau đó, bạn tạo tiếp 1 lớp mới là lớp StreetRacer thừa kế từ lớp Vehicle như sau:
public class StreetRacer extends Vehicle { }
Tới đây, chương trình của bạn vẫn hoàn toàn tốt đẹp. Bạn có thể khai báo 1 đối tượng StreetRacer và gọi tới hàm go:
$streetRacer = new StreetRacer; $streetRacer->go();
Và kết quả trả về là: Now I’m driving. Kết quả hoàn toàn chính xác. Nhưng sau đó, bạn nhận thêm 1 hợp đồng sản xuất máy bay trực thăng Helicopter. Bạn nhận thấy máy bay trực thăng thì cũng là 1 phương tiện vận chuyển. Vì vậy bạn quyết định tạo ra 1 lớp Helicopter thừa kế từ lớp Vehicle:
public class Helicopter extends Vehicle { }
Nhưng bạn chợt nhận ra vấn đề là khi sử dụng hàm go cho Helicopter, thì kết quả trả về có vẻ không chính xác. Now I’m driving? Tại sao máy bay lại là driving? Máy bay thì phải bay chứ nhỉ? Nhưng nó không phải là vấn đề lớn. Bạn quyết định sẽ override hàm go cho lớp Helicopter như sau:
public class StreetRacer extends Vehicle { public function go() { echo "Now I'm flying"; } }
Có vẻ vấn đề đã được giải quyết. Giờ thì máy bay đã là flying rồi. Nhưng vài tuần sau, khách hàng yêu cầu phải chuyển từ Now, I’m flying sang Now, I’m flying 200mph và nhiều sự thay đổi kế tiếp. Có một vấn đề nảy sinh ở đây. Đó chưa phải là một vấn đề lớn, nhưng nếu bạn phải xử lý các công việc này một cách khá thường xuyên, thì việc cứ phải chỉnh sửa các lớp con như thế này trờ thành 1 vấn đề bảo trì khá nghiêm trọng.
Bạn bắt đầu suy nghĩ. Có lẽ sự thừa kế không phải là cách giải quyết tốt cho tình huống này. Nơi mà bạn cần phải thay đổi các chức năng thường xuyên ở các lớp con. Và khi có càng nhiều lớp kế thừa liên quan, chúng cũng cần được bảo trì khi có sự thay đổi và khi đó, bạn sẽ phải cập nhất phương thức go nhiều lần.
Vấn đề bạn cần phải giải quyết ở đây là làm sao để tránh được việc thay đổi ở các lớp con, nếu không, bạn sẽ phải thay đổi code ở rất nhiều file để cập nhật được yêu cầu của khách hàng.
Có lẽ là bạn cần một cách khác tốt hơn để xử lý vấn đề này thay vì sử dụng thừa kế.