close up photo of programming of codes

codecungnhau.com

Một trang web về kỹ thuật lập trình

C++ Design patterns: Abstract Factory

Abstract Factory là một mẫu thiết kế khởi tạo, giải quyết vấn đề tạo ra toàn bộ họ sản phẩm mà không chỉ định các lớp cụ thể của chúng.

Abstract Factory định nghĩa một giao diện để tạo tất cả các sản phẩm riêng biệt nhưng để việc tạo sản phẩm thực tế cho các lớp factory cụ thể. Mỗi loại factory tương ứng với một loại sản phẩm nhất định.

Mã client gọi các phương thức khởi tạo của một đối tượng factory thay vì tạo sản phẩm trực tiếp bằng lệnh gọi phương thức khởi tạo (toán tử new). Vì một factory tương ứng với một biến thể sản phẩm duy nhất nên tất cả các sản phẩm của factory đó sẽ tương thích.

Client chỉ hoạt động với các factory và sản phẩm thông qua các giao diện trừu tượng của chúng. Điều này cho phép client hoạt động với mọi biến thể sản phẩm, được tạo bởi đối tượng factory. Bạn chỉ cần tạo một lớp factory cụ thể mới và chuyển nó cho client.

Cách sử dụng mẫu trong C++

Sử dụng: Mẫu Abstract Factory khá phổ biến trong C++. Nhiều framework và thư viện sử dụng nó để cung cấp cách mở rộng và tùy chỉnh các thành phần tiêu chuẩn của chúng.

Nhận biết: Mẫu dễ dàng được nhận ra bằng các phương thức trả về một đối tượng factory. Sau đó, factory được sử dụng để tạo ra các thành phần phụ cụ thể.

Chương trình minh họa

Ví dụ này minh họa cấu trúc của mẫu thiết kế Abstract Factory. Nó tập trung vào việc trả lời những câu hỏi sau:

  • Nó bao gồm những lớp nào?
  • Các lớp này có vai trò gì?
  • Các thành phần của mẫu có liên quan với nhau theo cách nào?

main.cpp

/**
 * Mỗi sản phẩm riêng biệt của một họ sản phẩm nên có một giao diên cơ sở.
 * Tất cả các biến thể của sản phẩm đều phải hiện thực giao diện này.
 */
class AbstractProductA {
 public:
  virtual ~AbstractProductA(){};
  virtual std::string UsefulFunctionA() const = 0;
};

/**
 * Concrete Product được tạo ra tương ứng với Concrete Factory.
 */
class ConcreteProductA1 : public AbstractProductA {
 public:
  std::string UsefulFunctionA() const override {
    return "The result of the product A1.";
  }
};

class ConcreteProductA2 : public AbstractProductA {
  std::string UsefulFunctionA() const override {
    return "The result of the product A2.";
  }
};

/**
 * Đây là giao diện cơ sở của một sản phẩm khác. Tất cả các sản phẩm có thể tương tác với nhau,
 * nhưng chỉ có thể thích hợp tương tác giữa các sản phẩm của cùng một biến thể cụ thể.
 */
class AbstractProductB {
  /**
   * Sản phẩm B có thể làm mọi thứ của nó...
   */
 public:
  virtual ~AbstractProductB(){};
  virtual std::string UsefulFunctionB() const = 0;
  /**
   * ...nhưng cũng có thể tương tác với sản phẩm A.
   *
   * Abstract Factory đảm bảo rằng tất cả các sản phẩm mà nó tạo ra đều 
   * có cùng một biến thể và do đó, tương thích.
   */
  virtual std::string AnotherUsefulFunctionB(const AbstractProductA &collaborator) const = 0;
};

/**
 * Concrete Product được tạo ra tương ứng bởi Concrete Factory.
 */
class ConcreteProductB1 : public AbstractProductB {
 public:
  std::string UsefulFunctionB() const override {
    return "The result of the product B1.";
  }
  /**
   * Biến thể, Sản phẩm B1, chỉ có thể hoạt động chính xác với biến thể, Sản phẩm A1. 
   * Tuy nhiên, nó chấp nhận bất kỳ thể hiện nào của AbstractProductA làm đối số.
   */
  std::string AnotherUsefulFunctionB(const AbstractProductA &collaborator) const override {
    const std::string result = collaborator.UsefulFunctionA();
    return "The result of the B1 collaborating with ( " + result + " )";
  }
};

class ConcreteProductB2 : public AbstractProductB {
 public:
  std::string UsefulFunctionB() const override {
    return "The result of the product B2.";
  }
  /**
   * Biến thể, Sản phẩm B2, chỉ có thể hoạt động chính xác với biến thể, Sản phẩm A2. 
   * Tuy nhiên, nó chấp nhận bất kỳ thể hiện nào của AbstractProductA làm đối số.
   */
  std::string AnotherUsefulFunctionB(const AbstractProductA &collaborator) const override {
    const std::string result = collaborator.UsefulFunctionA();
    return "The result of the B2 collaborating with ( " + result + " )";
  }
};

/**
 * Giao diện Abstract Factory khai báo một tập hợp các phương thức trả về các sản phẩm trừu 
 * tượng khác nhau. Những sản phẩm này được gọi là một họ và có liên quan với nhau theo 
 * một chủ đề hoặc khái niệm. Các sản phẩm của một họ thường có thể cộng tác với nhau. 
 * Một họ sản phẩm có thể có một số biến thể, nhưng các sản phẩm của biến thể này 
 * không tương thích với các sản phẩm của biến thể khác.
 */
class AbstractFactory {
 public:
  virtual AbstractProductA *CreateProductA() const = 0;
  virtual AbstractProductB *CreateProductB() const = 0;
};

/**
 * Các Concrete Factory sản xuất một họ sản phẩm thuộc một biến thể duy nhất. Nhà máy đảm 
 * bảo rằng các sản phẩm tạo ra là tương thích. Lưu ý rằng chữ ký của các phương thức của 
 * Concrete Factory trả về một sản phẩm trừu tượng (abstract product), trong khi bên trong 
 * phương thức, một sản phẩm cụ thể được khởi tạo.
 */
class ConcreteFactory1 : public AbstractFactory {
 public:
  AbstractProductA *CreateProductA() const override {
    return new ConcreteProductA1();
  }
  AbstractProductB *CreateProductB() const override {
    return new ConcreteProductB1();
  }
};

/**
 * Mỗi Concrete Factory có một biến thể sản phẩm tương ứng.
 */
class ConcreteFactory2 : public AbstractFactory {
 public:
  AbstractProductA *CreateProductA() const override {
    return new ConcreteProductA2();
  }
  AbstractProductB *CreateProductB() const override {
    return new ConcreteProductB2();
  }
};

/**
 * Mã Client chỉ hoạt động với các nhà máy và sản phẩm thông qua các kiểu trừu tượng: 
 * AbstractFactory và AbstractProduct. Điều này cho phép bạn truyền bất kỳ lớp con nào 
 * của nhà máy hoặc sản phẩm sang mã client mà không làm hỏng nó.
 */

void ClientCode(const AbstractFactory &factory) {
  const AbstractProductA *product_a = factory.CreateProductA();
  const AbstractProductB *product_b = factory.CreateProductB();
  std::cout << product_b->UsefulFunctionB() << "\n";
  std::cout << product_b->AnotherUsefulFunctionB(*product_a) << "\n";
  delete product_a;
  delete product_b;
}

int main() {
  std::cout << "Client: Testing client code with the first factory type:\n";
  ConcreteFactory1 *f1 = new ConcreteFactory1();
  ClientCode(*f1);
  delete f1;
  std::cout << std::endl;
  std::cout << "Client: Testing the same client code with the second factory type:\n";
  ConcreteFactory2 *f2 = new ConcreteFactory2();
  ClientCode(*f2);
  delete f2;
  return 0;
}

Kết quả:

Client: Testing client code with the first factory type:
The result of the product B1.
The result of the B1 collaborating with the (The result of the product A1.)

Client: Testing the same client code with the second factory type:
The result of the product B2.
The result of the B2 collaborating with the (The result of the product A2.)

Đã đăng vào

trong

, ,

bởi

Thẻ:

Bình luận

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *