Mẫu thiết kế (Design Patterns) là một chủ đề rất hay trong công nghệ phần mềm. Tuy nhiên sẽ rất khó khăn cho những người mới bước đầu tìm hiểu về nó. Để có thể hiểu và áp dụng được các mẫu thiết kế đòi hỏi người lập trình phải có kinh nghiệm về lập trình hướng đối tượng.
Mẫu thiết kế là một giải pháp tổng thể cho các vấn đề chung trong thiết kế phần mềm. Nó không phải là một chuẩn được quy định bởi một tổ chức nào cả mà chỉ là những thiết kế của các chuyên gia đã được sử dụng và được đánh giá tốt giúp giải quyết những vấn đề thiết kế thường gặp. Mẫu thiết kế chú trọng việc giúp phần mềm có tính uyển chuyển, dễ nâng cấp, thay đổi.
Mẫu thiết kế được phân loại ra thành 3 nhóm chính:
Structural Patterns: liên quan đến các vấn đề làm thế nào để các lớp và đối tượng kết hợp với nhau tạo thành các cấu trúc lớn hơn (gồm Adapter, Bridge, Composite, Decorator, …).
Creational Patterns: Khắc phục các vấn đề về khởi tạo đối tượng, hạn chế sự phụ thuộc nền tảng (gồm Factory, Abstract Factory, Singleton, Prototype, Builder…).
Behavioral Patterns: Mô tả cách thức để các lớp hoặc đối tượng có thể giao tiếp với nhau (gồm State, Observer, Strategy, Template, …).
Trong bài đầu tiên của loạt bài về Design Patterns này mình sẽ giới thiệu về mẫu Decorator của nhóm Structural.
Định nghĩa: Mẫu Decorator gắn kết thêm tính năng cho các đối tượng một cách linh hoạt. Nó cung cấp một phương pháp linh hoạt hơn là sử dụng các lớp con để mở rộng tính năng của đối tượng.
Tư tưởng của mẫu này là bạn sẽ bao bọc mã nguồn để mở rộng tính năng. Bạn không cần thiết phải chỉnh sửa mã nguồn cũ mà sẽ dùng những đối tượng mới bao bọc những đối tượng cũ để “trang trí” thêm cho đối tượng cũ.
Để minh họa, mình sẽ dùng một ví dụ đơn giản để các bạn dễ hình dung. Giả sử ban đầu bạn có 1 chiếc xe đạp:
Sau đó bạn muốn gắn thêm cho nó một chiếc tên lửa để nó chạy nhanh hơn:
Rồi sau đó bạn lại muốn gắn thêm cho nó một cái cánh quạt để nó có thể bay:
Dưới đây là đoạn mã nguồn minh họa cho ví dụ này. Bạn bắt đầu bằng việc viết mã nguồn cho lớp Bike.
     float load;
     public Bike(float velocity, float load)
     {
         this.Velocity = velocity;
         this.load = load;
     }
     public override void Run()
     {
         Console.WriteLine(“Van toc cua xe dap: ” + Velocity.ToString());
         Console.WriteLine(“Tai trong cua xe dap: ” + load.ToString());
     }
}
abstract class Component
{
     private float velocity;
     public float Velocity
     {
         get { return velocity; }
         set { velocity = value; }
     }
     public abstract void Run();
}
Ở trên, lớp Bike kế thừa từ lớp Component. Có thể ngay từ đầu bạn đã xác định cho Bike kế thừa như vậy, hoặc cũng có thể sau này lúc tinh chỉnh mã nguồn bạn có nhu cầu gắn thêm “đồ chơi” cho Bike thì mới tạo ra interface để nó kế thừa như trên. Điều này hoàn toàn phụ thuộc vào bạn.
Bây giờ chúng ta sẽ viết thêm một số class để “trang trí” cho Bike. Chúng ta tạo ra một lớp trừu tượng kế thừa từ Component, lớp này sẽ được những lớp con (chính là những “đồ chơi” mà ta muốn gắn thêm) kế thừa lại.
     protected Component comp;
     public Decorator(Component comp)
     {
         this.comp = comp;
     }
}
Giờ chúng ta sẽ tạo ra lớp Rocket để gắn thêm tên lửa cho xe đạp.
class Rocket : Decorator
{
     public Rocket(Component comp)
: base(comp)
     {
         this.comp.Velocity += 100;
     }
     public override void Run()
     {
         this.comp.Run();
     }
}
Và cuối cùng là cánh quạt.
     public Propeller(Component comp)
: base(comp)
     {
     }
     public override void Run()
     {
         this.comp.Run();
         Console.WriteLine(“Chiec xe dap da duoc gan canh quat va co the bay!”);
     }
}
Sau đó chúng ta sẽ lần lượt gắn những vật này cho Bike như sau:
bike.Run();
//Gắn thêm tên lửa cho xe đạp
Console.WriteLine(“\n========Gan them ten lua cho xe dap:========”);
Rocket bikeWithRocket = new Rocket(bike);
bikeWithRocket.Run();
//Gắn thêm cánh quạt cho xe đạp
Console.WriteLine(“\n========Gan them canh quat cho xe dap:========”);
Propeller bikeWithRocketAndPropeller = new Propeller(bikeWithRocket);
bikeWithRocketAndPropeller.Run();
Bạn có thể chạy đoạn mã nguồn trên và kết quả chúng ta nhận được như sau:
Bài hướng dẫn này mình chỉ trình bày tư tưởng cơ bản của Design Patterns và của mẫu Decorator. Các bạn có thể biến thể mẫu này đôi chút để phù hợp với nhu cầu sử dụng của mình. Chúc các bạn thành công!
Nguồn: Projectviet