Autolist design pattern

flower-pattern-illustrations-design-patterns-paintings-367221_50

Là một game programmer với vũ khí là C++, bạn hay có nhu cầu muốn tất cả các đối tượng thuộc kiểu lớp A trong chương trình đều được lưu vào trong một danh sách để tiện quản lý.

Nếu có nhiều lớp như lớp A, bạn sẽ phải tạo nhiều danh sách (có thể là mảng hoặc vector, map, set, …) => viết code nhiều, copy & paste nhiều => tiềm ẩn bug. Chưa kể trong trường hợp có lớp B kế thừa lớp A, thì phải nhớ thêm đối tượng kiểu B vào danh sách kiểu A (do một đối tượng kiểu B thì cũng thuộc kiểu A). Đừng xoắn nếu tôi lại nói có kiểu C kế thừa kiểu B :)

Vậy thì Autolist là một design pattern giúp bạn làm công việc trên hết sức tiện lợi. Bạn viết lớp Autolist như sau:

template<typename T>
class Autolist
{
public:
	Autolist()
	{
		T* p = (T*)this;
		// add con trỏ p vào danh sách của bạn
	}

	~Autolist()
	{
		T* p = (T*)this;
		// remove con trỏ p ra khỏi danh sách của bạn
	}

	// để không phụ thuộc vào cách cài đặt danh sách
	// chúng ta có 2 method sau đây (bắt chước iterator)

	static T* GetAutolistFirst()
	{
		// return con trỏ trỏ đến phần tử T đầu tiên
		// nếu danh sách rỗng thì return NULL
	}

	static T* GetAutolistNext()
	{
		// return con trỏ trỏ đến phần tử T kế tiếp
		// nếu đang ở cuối danh sách thì return NULL
	}

	// khai báo một danh sách tĩnh: mảng, vector, ... tùy ý,
	// để chứa các phần tử thuộc kiểu T*
};

Giờ giả sử có lớp A, bạn muốn lớp A được Autolist thì chỉ việc viết đơn giản:

class A : public Autolist<A>
{
};

Từ đây, mỗi khi bạn tạo một thể hiện của A: A a = new A(); thì constructor của lớp cha, tức là lớp Autolist<A> được gọi trước, vì con trỏ this thuộc kiểu A nên ép kiểu như trên là hợp lệ. Con trỏ trỏ đến thể hiện này được add vào một danh sách tĩnh bên trong lớp Autolist<A>.

Khi bạn hủy a: delete a, thì destructor của A được gọi trước, sau đó destructor của Autolist<A> được gọi, và con trỏ này được remove ra khỏi danh sách tĩnh bên trong lớp Autolist<A>.

Để duyệt qua danh sách các đối tượng kiểu A, viết:

A* t = Autolist<A>::GetAutolistFirst();
while (t)
{
	// làm gì đó với t
	t = Autolist<A>::GetAutolistNext();
}

Sẽ chẳng có vấn đề gì nếu bạn có tiếp lớp B kế thừa lớp A, lớp C kế thừa B, …

class B : public A, public Autolist<B>
{
};

class C : public B, public Autolist<C>
{
};

Các danh sách được compiler tạo ra tự động và việc add/remove các con trỏ trên những danh sách đó cũng tự động. Thích duyệt qua danh sách kiểu lớp nào, gọi Autolist<kiểu lớp đó>::GetAutolistFirst();

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s