Skip to main content

Chống lại sự phụ thuộc

Đây là 1 trong những nguyên tắc quan trọng trong phát triển phần mềm. Có rất nhiều framework thực hiện tốt được điều này như Ninject, Authofac, Stucture Map, MEF…
Trong bài viết này, mình không có tham vọng nêu rõ nguyên tắc lẫn cách sử dụng các framework, mà mình sẽ hướng dẫn từng bước chuyển đổi chương trình cho thật linh hoạt.
Bài toán: Có 2 loài động vật: sử tử và ngựa, sống trong rừng, Tazania hoặc sở thú. Mỗi con có duy nhất 1 phương thức là Running()
Ngựa sống trong rừng. Sử tử sống ở Tazania. Sở thú thì có cả 2 con, nhưng tại 1 thời điểm, họ chỉ cho phép 1 con thú chạy vòng vòng.
Theo cách viết thông thường, bạn sẽ viết cứng:
var forest = new Forest();
forest.Show();

Đây là lớp Forest
public class Forest
{
 private IAnimal _animal;

 public Forest()
 {
  _animal = new Horse();
  Console.WriteLine("---Forest---");
 }

 public void Show()
 {
  _animal.Running();
 }
}
Cách viết này có 1 điểm dở: Rừng bị phụ thuộc vào ngựa. Sau này muốn thay đổi thì phải vào sửa lớp Forest.

Cách 2

Ta viết lại lớp Tazania nhưng _animal không phụ thuộc vào lớp cố định
public class Tanzania
{
 private IAnimal _animal;

 public Tanzania(IAnimal animal)
 {
  _animal = animal;
  Console.WriteLine("---Tanzania---");
 }

 public void Show()
 {
  _animal.Running();
 }
}

Cách 3

Bạn sẽ sử dụng design Pattern Abstract Factory để giải quyết sự phụ thuộc.
Abstract Factory, đầy đủ là Abstract Factory pattern, là thiết kế mẫu hướng đối tượng trong việc thiết kế phần mềm cho máy tính, cung cấp một giao diện lớp có chức năng tạo ra một tập hợp các đối tượng liên quan hoặc phụ thuộc lẫn nhau mà không chỉ ra đó là những lớp cụ thể nào tại thời điểm thiết kế.
(Wikipedia)
Thay vì cài đặt, mình sẽ sử dụng AutoFac để đơn giản hóa vấn đề coding

static void RegisterAfrica()
{
 var builder = new ContainerBuilder();
 builder.RegisterType<Lion>().As<IAnimal>();
 Container = builder.Build();
}

static void RegisterAsia()
{
 var builder = new ContainerBuilder();
 builder.RegisterType<horse>().As<IAnimal>();
 Container = builder.Build();
}

static void ParticularExample()
{
 RegisterAfrica();
 using (var scope = Container.BeginLifetimeScope())
 {
  var zoo = new Zoo(scope.Resolve<IAnimal>());
  zoo.Show();
 }            
}
Để gọi loài động vật tương ứng, bạn gọi hàm Register().
Trong ví dụ này, có lẽ bạn chưa thấy được công dụng của việc chống lại sự phụ thuộc. Nhưng giả sử bạn viết 1 phần mềm. Giai đoạn đầu, bạn sử dụng LinQ, sau này chuyển qua Entity Framework, và nó được implement rất nhiều chỗ. Thông qua hàm Register() duy nhất, bạn có thể chuyển đổi dễ dàng mà không sợ bị lỗi. Viết theo cách 1, bạn phải sửa đổi tất cả các lớp, viết theo cách 2, bạn phải sửa đổi giá trị khi truyền vào hàm khởi tạo. Viết theo cách 3, bạn chỉ sửa hàm Register().
Hi vọng bài viết này sẽ hữu ích với các bạn
Demo: MediaFire

Comments

Popular posts from this blog

Lập trình đa luồng với Task

Bài viết được đăng trên Jou Lập trình
Trong phiên bản .NET framework 4.0, Microsoft đã bổ sung nhiều thư viện hỗ trợ việc xử lý đa luồng (multi-threading), nhằm đơn giản hóa việc lập trình lẫn hiệu suất của chương trình. Trong bài viết này, tôi xin hướng dẫn các bạn sử dụng lớp System.Threading.Task.

Tìm hiểu về IdentityServer 4

Trong bài viết này, mình sẽ hướng dẫn các bạn làm quen với thư viện Identity Server 4, và tích hợp các service In-Memory của Identity Server 4 vào Project Web API trong .NET Core.

[ASP.NET MVC] Authentication và Authorize

Một trong những vấn đề bảo mật cơ bản nhất là đảm bảo những người dùng hợp lệ truy cập vào hệ thống. ASP.NET đưa ra 2 khái niệm: Authentication và Authorize
Authentication xác nhận bạn là ai. Ví dụ: Bạn có thể đăng nhập vào hệ thống bằng username và password hoặc bằng ssh.
Authorization xác nhận những gì bạn có thể làm. Ví dụ: Bạn được phép truy cập vào website, đăng thông tin lên diễn đàn nhưng bạn không được phép truy cập vào trang mod và admin.