close up photo of programming of codes

codecungnhau.com

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

C++ Design Patterns: Prototype (Clone)

Prototype là một mẫu thiết kế khởi tạo cho phép sao chép các đối tượng, ngay cả những đối tượng phức tạp, mà không cần ghép nối với các lớp cụ thể của chúng.

Tất cả các lớp prototype phải có một giao diện chung để có thể sao chép các đối tượng ngay cả khi các lớp cụ thể của chúng là không xác định. Các đối tượng prototype có thể tạo ra các bản sao đầy đủ vì các đối tượng của cùng một lớp có thể truy cập vào các trường riêng tư của nhau.

Cách sử dụng mẫu

Sử dụng: Mẫu Prototype có sẵn trong C++ với giao diện có thể sao chép.

Nhận biết: Prototype có thể dễ dàng nhận ra bằng phương thức clone hoặc copy, v.v.

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ế Prototype. 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

using std::string;
// Cho phép bạn sao chép các đối tượng hiện có mà không làm cho mã của bạn
// phụ thuộc vào các lớp của chúng.
enum Type {
  PROTOTYPE_1 = 0,
  PROTOTYPE_2
};
/**
 * Lớp Prototype có khả năng nhân bản. Chúng ta sẽ xem các giá trị của cácc trường
 * với các kiểu khác nhau sẽ được sao chép như thế nào.
 */
class Prototype {
 protected:
  string prototype_name_;
  float prototype_field_;
 public:
  Prototype() {}
  Prototype(string prototype_name)
      : prototype_name_(prototype_name) {
  }
  virtual ~Prototype() {}
  virtual Prototype *Clone() const = 0;
  virtual void Method(float prototype_field) {
    this->prototype_field_ = prototype_field;
    std::cout << "Call Method from " << prototype_name_ << " with field : " << prototype_field << std::endl;
  }
};
/**
 * ConcretePrototype1 là một lớp con của prototype và thực hiện phương thức clone.
 * Trong ví dụ này, tất cả các dữ liệu thành viên của lớp prototype đều nằm trong stack.
 * Nếu bạn có con trỏ trong thuộc tính của mình cho ví dụ: String * name_, bạn sẽ cần
 * triển khai Copy-Constructor để đảm bảo có một deep copy từ phương thức clone.
 */
class ConcretePrototype1 : public Prototype {
 private:
  float concrete_prototype_field1_;
 public:
  ConcretePrototype1(string prototype_name, float concrete_prototype_field)
      : Prototype(prototype_name), concrete_prototype_field1_(concrete_prototype_field) {
  }
  /**
   * Lưu ý rằng phương thức Clone trả về một con trỏ đến một bản sao ConcretePrototype1 mới. 
   * Do đó, client (người gọi phương thức clone) có trách nhiệm giải phóng bộ nhớ đó. Nếu bạn
   * có kiến thức về smart pointer, bạn có thể sử dụng unique_pointer ở đây.
   */
  Prototype *Clone() const override {
    return new ConcretePrototype1(*this);
  }
};
class ConcretePrototype2 : public Prototype {
 private:
  float concrete_prototype_field2_;
 public:
  ConcretePrototype2(string prototype_name, float concrete_prototype_field)
      : Prototype(prototype_name), concrete_prototype_field2_(concrete_prototype_field) {
  }
  Prototype *Clone() const override {
    return new ConcretePrototype2(*this);
  }
};
/**
 * Trong PrototypeFactory, bạn có hai prototype cụ thể, một cho mỗi lớp prototype cụ thể,
 * vì vậy mỗi lần bạn muốn khởi tạo, bạn có thể sử dụng những prototype hiện có và
 * sao chép chúng.
 */
class PrototypeFactory {
 private:
  std::unordered_map<Type, Prototype *, std::hash<int>> prototypes_;
 public:
  PrototypeFactory() {
    prototypes_[Type::PROTOTYPE_1] = new ConcretePrototype1("PROTOTYPE_1 ", 50.f);
    prototypes_[Type::PROTOTYPE_2] = new ConcretePrototype2("PROTOTYPE_2 ", 60.f);
  }
  /**
   * Hãy cẩn thận về việc giải phóng tất cả bộ nhớ được cấp phát. Một lần nữa, 
   * nếu bạn có kiến thức về smart pointer thì tốt hơn sử dụng nó ở đây.
   */
  ~PrototypeFactory() {
    delete prototypes_[Type::PROTOTYPE_1];
    delete prototypes_[Type::PROTOTYPE_2];
  }
  /**
   * Lưu ý ở đây rằng bạn chỉ cần chỉ định kiểu prototype bạn muốn 
   * và phương thức sẽ tạo từ đối tượng có kiểu này.
   */
  Prototype *CreatePrototype(Type type) {
    return prototypes_[type]->Clone();
  }
};
void Client(PrototypeFactory &prototype_factory) {
  std::cout << "Let's create a Prototype 1\n";
  Prototype *prototype = prototype_factory.CreatePrototype(Type::PROTOTYPE_1);
  prototype->Method(90);
  delete prototype;
  std::cout << "\n";
  std::cout << "Let's create a Prototype 2 \n";
  prototype = prototype_factory.CreatePrototype(Type::PROTOTYPE_2);
  prototype->Method(10);
  delete prototype;
}
int main() {
  PrototypeFactory *prototype_factory = new PrototypeFactory();
  Client(*prototype_factory);
  delete prototype_factory;
  return 0;
}

Kết quả:

Let's create a Prototype 1
Call Method from PROTOTYPE_1  with field : 90
Let's create a Prototype 2 
Call Method from PROTOTYPE_2  with field : 10

Đã đăng vào

trong

,

bởi

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 *