Search…

Design Pattern: Prototype Pattern

25/09/20205 min read
Prototype Pattern là một Pattern thuộc nhóm Creational Patterns, ý tưởng này là một design pattern đặc biệt có liên quan đến việc khởi tạo Object.

Prototype Pattern là gì ? 

Prototype Pattern là một trong những pattern phổ biến trong lập trình hướng đối tượng, là một pattern thuộc nhóm Creational Patterns. Ý tưởng này là một design pattern đặc biệt có liên quan đến việc khởi tạo đối tượng (Object), thay vì tạo ra Object, Prototype pattern sử dụng việc cloning (copy nguyên mẫu của Object). 

Ý tưởng

Hiện thực Prototype pattern bằng cách cung cấp một Object và dùng chính Object này như là một hình mẫu (template) khi cần tạo đối tượng mới. Việc tạo một Object mới sẽ dựa trên Object mẫu mà không sử dụng toán tử new hay constructor được cung cấp bởi ngôn ngữ lập trình. Mục đích che giấu thông tin của Object chỉ cung cấp ra bên ngoài một lượng thông tin giới hạn. Vì vậy không thể dùng toán tử new và sao chép những dữ liệu được Object cung cấp (vốn không đầy đủ) cho một Object mới. Cách tốt nhất là để Object "mẫu" tự xác định thông tin và dữ liệu sao chép.

Triển khai

Để cài đặt Prototype Pattern, tạo một phương thức Clone() ở lớp cha và triển khai ở các lớp con.

 Có 2 kiểu nhân bản trong prototype:

  • Shallow coppy: chỉ nhân bản được value type.
  • Deep coppy: nhân bản được value type và reference type.
Untitled

 

Prototype pattern gồm 3 phần:

  1. Client class: tạo mới Object bằng cách gọi Prototype thực hiện clone chính nó.
  2. Prototype: khai báo một Interface hoặc Abtract class cho việc clone chính nó.
  3. ConcretePrototype: triển khai những Operation cho việc clone chính nó.

Quá trình sao chép bắt đầu với việc khởi tạo class sẽ lấy làm mẫu.

Client class yêu cầu một object mới của loại đó và gửi yêu cầu tới class Prototype.

Một ConcretePrototype (phụ thuộc vào loại object mà Client cần) đảm nhận sao chép object client thông qua phương thức Clone(), khi đó một object mới thuộc loại Client sẽ được tạo ra.

Ưu điểm

  • Tránh việc tạo nhiều lớp con cho mỗi đối tượng tạo như của Abstract Factory Pattern.
  • Giảm chi phí để tạo ra một đối tượng mới theo "chuẩn", điều này sẽ làm tăng hiệu suất so với việc sử dụng từ khóa new để tạo đối tượng mới.
  • Khởi tạo object mới bằng cách thay đổi một vài thuộc tính của object (các object có ít điểm khác biệt nhau): 1 hệ thống linh động có khả năng cho phép tự định nghĩa một hành động nào đó thông qua sự kết hợp với một object (nghĩa là một phương thức của một class) hơn là định nghĩa một class mới. Client có thể thể hiện một tác động khác bằng cách ủy quyền cho lớp prototype. Đồng thời cách thức khởi tạo này cũng khai báo một "lớp mới" mà không phải lập trình gì cả. Thực tế thì việc copy một nguyên mẫu giống như việc khởi tạo một object từ một class mới. Prototype pattern giúp giảm số lớp mà hệ thống cần dùng.
  • Khởi tạo object mới bằng cách thay đổi cấu trúc: Rất nhiều ứng dụng xây dựng hệ thống từ nhiều phần và các phần con. Các phần con lại khởi tạo từ nhiều phần con khác (chia nhỏ bài toán). Prototype pattern cũng hỗ trợ điều này. Nghĩa là các phần đó có thể được khởi tạo từ việc copy một nguyên mẫu từ một "cấu trúc" khác. Miễn là các phần kết hợp đều thể hiện Clone() và được sử dụng với cấu trúc khác nhau làm nguyên mẫu.
  • Giảm việc phân lớp: Đôi khi hệ thống quá phức tạp vì có quá nhiều class, và cây thừa kế của lớp khởi tạo có quá nhiều lớp song song cùng mức. Prototype pattern rõ ràng làm giảm số lớp và sự phức tạp của cây thừa kế (class hierarchy).

Cài đặt

#include <iostream>
#include <string>

/* Prototype base class. */
class Prototype
{
protected:
	std::string type;
	int value;

public:
	virtual Prototype* clone() = 0;

	std::string getType()
	{
		return type;
	}

	int getValue()
	{
		return value;
	}
};

class ConcretePrototype1 : public Prototype
{
public:
	ConcretePrototype1(int number)
	{
		type = "Type1";
		value = number;
	}

	Prototype* clone()
	{
		return new ConcretePrototype1(*this);
	}
};

class ConcretePrototype2 : public Prototype
{
public:
	ConcretePrototype2(int number)
	{
		type = "Type2";
		value = number;
	}

	Prototype* clone()
	{
		return new ConcretePrototype2(*this);
	}
};

/* Factory that manages prorotype instances and produces their clones. */
class ObjectFactory
{
	static Prototype* type1value1;
	static Prototype* type1value2;
	static Prototype* type2value1;
	static Prototype* type2value2;

public:
	static void  initialize()
	{
		type1value1 = new ConcretePrototype1(1);
		type1value2 = new ConcretePrototype1(2);
		type2value1 = new ConcretePrototype2(1);
		type2value2 = new ConcretePrototype2(2);
	}

	static Prototype* getType1Value1()
	{
		return type1value1->clone();
	}

	static Prototype* getType1Value2()
	{
		return type1value2->clone();
	}

	static Prototype* getType2Value1()
	{
		return type2value1->clone();
	}

	static Prototype* getType2Value2()
	{
		return type2value2->clone();
	}
};

Prototype* ObjectFactory::type1value1 = 0;
Prototype* ObjectFactory::type1value2 = 0;
Prototype* ObjectFactory::type2value1 = 0;
Prototype* ObjectFactory::type2value2 = 0;

int main()
{
	ObjectFactory::initialize();
	Prototype* object;

	/* All the object were created by cloning the prototypes. */
	object = ObjectFactory::getType1Value1();
	std::cout << object->getType() << ": " << object->getValue() << std::endl;

	object = ObjectFactory::getType1Value2();
	std::cout << object->getType() << ": " << object->getValue() << std::endl;

	object = ObjectFactory::getType2Value1();
	std::cout << object->getType() << ": " << object->getValue() << std::endl;

	object = ObjectFactory::getType2Value2();
	std::cout << object->getType() << ": " << object->getValue() << std::endl;

	return 0;
}
IO Stream

IO Stream Co., Ltd

30 Trinh Dinh Thao, Hoa Thanh ward, Tan Phu district, Ho Chi Minh city, Vietnam
+84 28 22 00 11 12
developer@iostream.co

383/1 Quang Trung, ward 10, Go Vap district, Ho Chi Minh city
Business license number: 0311563559 issued by the Department of Planning and Investment of Ho Chi Minh City on February 23, 2012

©IO Stream, 2013 - 2024