Decorator pattern

Một hôm lang thang ở Trần Duy Hưng, Bụng đói mốc meo, cờ him cũng mốc nốt. Bỗng một em xinh tươi mời mình vào ăn bún riêu cua bò. Qua một hồi tán tỉnh em biết mình là một lập trình viên nên nhờ mình viết cho ẻm phần mềm quản lý cho quán cùng với lời hứa giúp cờ him mình hết mốc. Vốn kinh nghiệm đầy mình với bao nhiêu công nghệ trên tay mình nhận lời không một chút suy nghĩ và về suy nghĩ cách làm ngay một chương trình tặng nàng.

Quán em bán bún riêu nên mình tạo một lớp Bún Riêu.


   public class BunRieu
    {
        public virtual string DienTa()
        {
            return "Day la bun rieu";
        }
    }

Sau đó có người muốn ăn bún riêu có thêm bò. ờ chả sao mình tạo thêm một lớp bún riêu có bò, kế thừa từ bún riêu là xong hehe đơn giản


 public class BunRieuBo:BunRieu
{
public override string DienTa()
{
return base.DienTa()+ ", bò";
}
}

Sau đó có người muốn ăn bún riêu có cả bò cả giò, Ok không sao cả mình lại thêm một lớp bún riêu bò giò kế thừa từ bún riêu bò , mọi thứ vẫn cứ là OK.


 public class BunRieuBoGio : BunRieuBo
{
public override string DienTa()
{
return base.DienTa() + ", giò";
}
}

Nhưng mà khách hàng có thể thêm Ốc, Đậu, Rau Sống, Rau Trần,… Hoặc chỉ ốc không bò, chỉ giò với riêu … Như thế với mỗi trường hợp tôi lại phải thêm một class mới. Ôi mẹ ơi code thế này bao giờ mới xong, làm sao để tôi có thể cho em ấy chữa bệnh mốc cờ him được chứ.

Đúng lúc bế tắc, ông tơ bà nguyệt hiện lên và bảo, con ơi hãy dùng mẫu Trang Trí (Decorator) tình yêu sẽ đến.

Vậy là tôi tiếp xúc với mẫu này, ôi ông Tơ bà Nguyệt ơi nó dùng tốt cho trường hợp của tôi. Vậy là tôi bắt đầu ngâm cứu để chữa bệnh mốc cờ him. Ý tưởng mẫu này như sau. Phần này tôi xin đi chi tiết chút về kỹ thuật

decorator

  • Component   (IBunRieu ) Đinh Nghĩa một Interface cho các class khác kế thừa
  • ConcreteComponent   (Bún riêu) Định Nghĩa một object cho phép thêm các hành xử khác  vào
  • Decorator   (Decorator) Cái này là một abstract class để chứa các tham chiếu tới một đối tượng của Component
  •  ConcreteDecorator   (Bún riêu cua bò, bún riêu bò giò ) thêm các  hành xử thêm vào cho Component.

Giải thích mấy cái này khó bỏ mẹ, thôi vào ví dụ luôn và ngay cho dễ hiểu

Đầu tiên tạo Component cái đã

   public interface IBunRieu
    {
        string DienTa();
    }

Sau đó tạo ConcreteComponent


public class BunRieu:IBunRieu
{
public virtual string DienTa()
{
return "Day la bun rieu";
}
}

Tạo Decorator, cái này nghĩa là trang trí, ý nghĩa để thêm nhiều thứ vào để trang trí thêm cho ConcreteComponent như thêm bò, ốc, đậu, rau…

 


public abstract class Decorator : IBunRieu
{
private IBunRieu _bunrieu;

public Decorator(IBunRieu bunRieu)
{
_bunrieu = bunRieu;
}

public virtual string DienTa()
{
return _bunrieu.DienTa();
}
}

Nào bây giờ khách hàng buốn ăn riêu bò thì ta tạo thêm lớp riêu cua bò, kế thừa trực tiếp từ Decorator


public class BunRieuBo : Decorator
{
public BunRieuBo(IBunRieu bunRieu):base( bunRieu)
{

}

public override string DienTa()
{
return base.DienTa()+", Bo";
}
}

Nếu muốn thêm giò ta chỉ cần overide Decorator với đầu vào là bún riêu bò ta sẽ có ngay bún riêu giò bò mà không cần phải tạo class bún riêu giò bò. Vậy ta chỉ cân tạo những class Bún Riêu, Bún Riêu Bò, Bún Riêu Giò, Bún Riêu Đậu chứ không cần tạo các class kết hợp của chúng nữa, code sẽ dễ hơn. Để mình ví dụ tiếp


public class BunRieuGio : Decorator
{
public BunRieuGio(IBunRieu bunRieu) : base(bunRieu)
{

}

public override string DienTa()
{
return base.DienTa() + ", gio";
}
}

public class BunRieuDau : Decorator
{
public BunRieuDau(IBunRieu bunRieu) : base(bunRieu)
{

}

public override string DienTa()
{
return base.DienTa() + ", dau";
}
}

public class BunRieuRau : Decorator
{
public BunRieuRau(IBunRieu bunRieu) : base(bunRieu)
{

}

public override string DienTa()
{
return base.DienTa() + ", rau";
}
}

Giờ đây khi ta muốn một bán bún riêu đầy đủ chỉ cần


static void Main(string[] args)
{
var bunRieu = new BunRieu();
var bunRieuDayDu = new BunRieuBo(new BunRieuDau(new BunRieuRau(new BunRieuGio(bunRieu))));
Console.WriteLine( bunRieuDayDu.DienTa());
Console.Read();
}

Kết quả

Day la bun rieu, gio, rau, dau, Bo

Ta cũng có thể tùy biến tổ hợp các món này một cách đơn giản hơn rất nhiều ví dụ., Bún riêu bò có đậu, bún riêu bò có giò …. chỉ bằng Decorator chứ không cần tạo nhiều class như trước nữa.

Có thể có bạn sẽ hỏi sao không vào trực tiếp lớp bún riêu mà thêm các phương thức thêm giò thêm đậu …. Thì theo nguyên tắc SOLID , một lớp thiết kế để dễ mở rộng và khó sửa đổi, khi lập trình nếu ta chỉ thêm code mà không sửa code cũ sẽ ít dẫn tới lỗi và phạm vi test sẽ nhỏ hơn, vì vậy với mẫu decorate này  cung cấp một cách để thêm các hành xử, đặc điểm vào đối tượng lúc runtime mà không phải kế thừa nhiều, cũng như tạo nhiều class rối rắm phức tạp, dễ code hơn và dễ bảo trì hơn. Trong thực tế mẫu này được sử dụng trong windows, hay trong game. Biết đâu một ngày nào đó bạn sẽ sử dụng nó trong code của mình.

Thôi đến giờ mình gửi chương trình cho em xinh tươi ở Trần Duy Hưng đây, tạm biệt các bạn. Để xem  thêm về design pattern có thể xem tại đây nhé!

 

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Đăng xuất /  Thay đổi )

Google photo

Bạn đang bình luận bằng tài khoản Google Đăng xuất /  Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Đăng xuất /  Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Đăng xuất /  Thay đổi )

Connecting to %s

Tạo một website miễn phí hoặc 1 blog với WordPress.com.

Up ↑

%d bloggers like this: