Design pattern: Abstract Factory (phần 1)

Design pattern: Abstract Factory (phần 1)

Abstract factory là một trong các design pattern được áp dụng khá phổ biến trong khi thiết kế và lập trình. Nó cung cấp một cách thức chung để tạo ra một họ các đối tượng có quan hệ hoặc phụ thuộc nhau mà không cần chỉ rõ các lớp cụ thể trong họ đó.

UML

Abstract factory được mô hình hóa bởi UML như sau:
UML: Abstract Factory

Các thành phần tham gia

  • AbstractFactory: Khai báo dạng interface hoặc abstract class chứa các phương thức để tạo ra các đối tượng abstract
  • ConcreteFactory: Xây dựng, cài đặt các phương thức tạo các đối tượng cụ thể
  • AbstractProduct: Khai báo dạng interface hoặc abstract class để định nghĩa đối tượng abstract
  • Product: Cài đặt của các đối tượng cụ thể, cài đặt các phương thức được quy định tại AbstractProduct
  • Client: là đối tượng sử dụng AbstractFactory và các AbstractProduct

Cài đặt AbstractFactory trong C#

Ta thực hiện cài đặt lần lượt các lớp trong mô hình UML trên bằng C#. Để đơn giản, AbstractProductA không chứa hàm nghiệp vụ nào, AbstractProductB chứa 1 hàm nghiệp vụ là Interact nhận tham số đầu vào là AbstractProductA và in ra màn hình thông báo tên lớp thực sự của AbstractProductB và AbstractProductA:

class MainApp
{
	public static void Main()
	{
		// Abstract factory #1
		AbstractFactory factory1 = new ConcreteFactory1();
		Client client1 = new Client(factory1);
		client1.Run();

		// Abstract factory #2
		AbstractFactory factory2 = new ConcreteFactory2();
		Client client2 = new Client(factory2);
		client2.Run();

		Console.ReadKey();
	}
}

//The 'AbstractFactory' abstract class
abstract class AbstractFactory
{
	public abstract AbstractProductA CreateProductA();
	public abstract AbstractProductB CreateProductB();
}

// The 'ConcreteFactory1' class
class ConcreteFactory1 : AbstractFactory
{
	public override AbstractProductA CreateProductA()
	{
		return new ProductA1();
	}
	public override AbstractProductB CreateProductB()
	{
		return new ProductB1();
	}
}

// The 'ConcreteFactory2' class
class ConcreteFactory2 : AbstractFactory
{
	public override AbstractProductA CreateProductA()
	{
		return new ProductA2();
	}
	public override AbstractProductB CreateProductB()
	{
		return new ProductB2();
	}
}

// The 'AbstractProductA' abstract class.
// Không chứa nghiệp vụ gì
abstract class AbstractProductA
{
}

// The 'AbstractProductB' abstract class
abstract class AbstractProductB
{
	// In ra màn hình thông báo tên lớp thực sự của AbstractProductB và AbstractProductA
	public abstract void Interact(AbstractProductA a);
}

// The 'ProductA1' class
class ProductA1 : AbstractProductA
{
}

// The 'ProductB1' class
class ProductB1 : AbstractProductB
{
	public override void Interact(AbstractProductA a)
	{
		Console.WriteLine(this.GetType().Name + " interacts with " + a.GetType().Name);
	}
}

// The 'ProductA2' class
class ProductA2 : AbstractProductA
{
}

// The 'ProductB2' class
class ProductB2 : AbstractProductB
{
	public override void Interact(AbstractProductA a)
	{
		Console.WriteLine(this.GetType().Name + " interacts with " + a.GetType().Name);
	}
}

// The 'Client' class.
class Client
{
	private AbstractProductA _abstractProductA;
	private AbstractProductB _abstractProductB;

	// Constructor
	public Client(AbstractFactory factory)
	{
		_abstractProductB = factory.CreateProductB();
		_abstractProductA = factory.CreateProductA();
	}

	public void Run()
	{
		_abstractProductB.Interact(_abstractProductA);
	}
}

Kết quả:

ProductB1 interacts with ProductA1
ProductB2 interacts with ProductA2

Nhận xét: Abstract Factory dựa trên tính thừa kế và đa hình đề cài đặt và sử dụng.

Một ví dụ trong thực tế

Có một bài toán thực tế và cần mô phỏng lại như sau: Trong thế giới động vật (AnimalWorld) có các loài động vật ăn cỏ (Herbivore) và các loài động vật ăn thịt (Carnivore). Ở mỗi châu lục (Continent) lại có các loài đặc thù khác nhau thuộc 2 nhóm trên. Ví dụ ở châu Phi (Africa) có Sư tử (Lion) và Dê núi (Wildebeest), châu Mỹ (America) có Sói (Wolf) và Bò rừng Bi-dông (Bison). Biết rằng bọn ăn thịt chỉ ăn những loài nó biết.
Ta sẽ áp dụng Abstract Factory để mô phỏng lại bài toán trên. Tôi sử dụng C# và cách thức cài đặt như bên trên trong đó lớp Herbivore cũng không có nghiệp vụ gì và lớp Carnivore có phương thức Eat (thực hiện in ra con gì ăn con gì).

class MainApp
{
	public static void Main()
	{
		// Tạo ra các loài động vật ở châu Phi
		ContinentFactory africa = new AfricaFactory();
		AnimalWorld world = new AnimalWorld(africa);
		world.RunFoodChain();

		// Tạo ra các loài động vật ở châu Mỹ
		ContinentFactory america = new AmericaFactory();
		world = new AnimalWorld(america);
		world.RunFoodChain();

		Console.ReadKey();
	}
}
// The 'AbstractFactory' abstract class
abstract class ContinentFactory
{
	// tạo ra động vật ăn cỏ
	public abstract Herbivore CreateHerbivore();
	// tạo ra động vật ăn thịt
	public abstract Carnivore CreateCarnivore();
}

// The 'ConcreteFactory1' class
class AfricaFactory : ContinentFactory
{
	public override Herbivore CreateHerbivore()
	{
		return new Wildebeest();
	}

	public override Carnivore CreateCarnivore()
	{
		return new Lion();
	}
}

// The 'ConcreteFactory2' class
class AmericaFactory : ContinentFactory
{
	public override Herbivore CreateHerbivore()
	{
		return new Bison();
	}

	public override Carnivore CreateCarnivore()
	{
		return new Wolf();
	}
}

// The 'AbstractProductA' abstract class
abstract class Herbivore
{
}

// The 'AbstractProductB' abstract class
abstract class Carnivore
{
	public abstract void Eat(Herbivore h);
}

// The 'ProductA1' class
class Wildebeest : Herbivore
{
}

// The 'ProductB1' class
class Lion : Carnivore
{
	public override void Eat(Herbivore h)
	{
		// Eat Wildebeest
		Console.WriteLine(this.GetType().Name +  " eats " + h.GetType().Name);
	}
}

// The 'ProductA2' class
class Bison : Herbivore
{
}

// The 'ProductB2' class
class Wolf : Carnivore
{
	public override void Eat(Herbivore h)
	{
		// Eat Bison
		Console.WriteLine(this.GetType().Name + " eats " + h.GetType().Name);
	}
}

// The 'Client' class
class AnimalWorld
{
	private Herbivore _herbivore;
	private Carnivore _carnivore;

	// Constructor
	public AnimalWorld(ContinentFactory factory)
	{
		_carnivore = factory.CreateCarnivore();
		_herbivore = factory.CreateHerbivore();
	}

	public void RunFoodChain()
	{
		_carnivore.Eat(_herbivore);
	}
}

Kết quả:

Lion eats Wildebeest
Wolf eats Bison
Khi trích dẫn bài viết từ tek.eten.vn, xin vui lòng ghi rõ nguồn. Chúng tôi sẽ rất cảm ơn bạn!