Lập trình hướng đối tượng – Bài tập – Quan hệ hợp thành dạng đệ qui

Lập trình hướng đối tượng – Bài tập – Quan hệ hợp thành dạng đệ qui

Bài viết này của tôi nằm trong series ‘các bài tập tham khảo’. Series này chia sẻ một số cách tiếp cận, hiện thực mức căn bản nhất, tóm tắt nhất các bài tập, bài tập lớn ngành Khoa học máy tính, trường ĐH Mở Tp.HCM.

Ngoài kĩ thuật lập trình, cấu trúc dữ liệu thì lập trình hướng đối tượng là một trong những môn lập trình trọng yếu của ngành khoa học máy tính. Với việc dùng ngôn ngữ hiện thực chủ đạo là C++, sinh viên có thể hiểu rõ cách thức hoạt động của đối tượng, bộ nhớ. Đồng thời C++ phiên bản 11 cũng đang là một ngôn ngữ mạnh mẽ đang được nhiều sự chú ý từ các lập trình viên.

Hy vọng bài viết này sẽ giúp các bạn ôn tập lại hiện thực quan hệ hợp thành đệ qui trong lập trình hướng đối tượng. 

1.      Giới thiệu

a.      Đề bài

Với sơ đồ lớp như hình vẽ, thực hiện các yêu cầu sau:

clip_image001

Cài đặt các lớp MenuItem, Menu, RadioMenuItem theo sơ đồ lớp nêu trên (Giải pháp cài đặt phải cho phép giải quyết bài toán ở câu 3).

Xây dựng ứng dụng đơn giản thực hiện các thao tác sau: (console application)

1.  Tạo một menu (và các phần tử con của menu, các phần tử con có thể là MenuItem, Menu, RadioMenuItem).

2.  Hiển thị menu vừa tạo.

3.  Liệt kê các RadioMenuItem đang ở trạng thái được chọn (selected = true).

 

Ý nghĩa của các thao tác thể hiện trên sơ đồ:

·         Show: hiển thị phần tử menu, hình thức hiển thị tùy thuộc loại phần tử.

Loại phần tử

Hình thức hiển thị

Ghi chú

MenuItem

Hiển thị phần label

 

Menu

Hiển thị phần label, và hiển thị các phần tử con.

 

RadioMenuItem

Hiển thị phần label, và dấu hiệu thể hiện trạng thái selected.

Dấu hiệu selected đặt trước phần label và có dạng:

( ): trường hợp selected = false

(o): trường hợp selected = true

·         Add: thêm các phần tử vào menu .

·         Select: thay đổi trạng thái selected.

·         IsSelected: kiểm tra phần tử đang ở trạng thái được chọn (selected = true).

(Sinh viên tự quyết định dạng đặc tả của các thao tác nêu trên)

Sinh viên tự thiết kế bổ sung các thao tác khác để đáp ứng yêu cầu của bài toán.

 

b.      Các kiến thức sử dụng

C++ 11

Thư viện STL

 

2.      Cài đặt

Thiết kế đã cho sẵn, nên ta hình dung ngay đó là quan hệ hợp thành đệ qui. Đọc một số sách về design pattern sẽ thấy quan hệ này áp dụng rất nhiều. Ví dụ như Composite Pattern.

Một Menu chứa nhiều MenuItem. 1 MenuItem có thể là Menu vừa, có thể là RadioMenuItem, hay chỉ là MenuItem đơn thuần.

Từ mô hình OMT như đề bài đã cho, ta thấy sẽ có ít nhất 3 lớp:

          MenuItem

          Menu

          RadioMenuItem

MenuItem sẽ là lớp cơ sở cho Menu và RadioMenuItem kế thừa. Ta khởi đầu bằng việc tạo các lớp bằng cách ứng với 1 lớp ta tạo 1 cặp file header và source.

Theo đề bài, Menu và RadioMenuItem  đều có chứa label và phương thức Show. Đồng thời đề bài muốn quản lý, hiển thị các đối tượng khác kiểu trong cùng một danh sách (subitems).  Vì vậy, label của MenuItem sẽ được để protected và phương thức Show sẽ là virtual để có thể áp dụng cơ chế đa hình.

 

Các phương thức đơn giản như Add, Select, IsSelected đơn giản nên ta sẽ thực hiện trước.

 

          Với chức năng Show, ta cần hệ thống và giải quyết từng bước một.

 

+ Vấn đề gọi đệ qui lấy ra toàn bộ các cấp con của Menu:  

 

clip_image003

 

+ Menu cần được hiển thị có cấu trúc phân cấp:

clip_image004

Vì vậy, phương thức Show cần phải nhận thêm 1 tham số là cấp độ hay đại loại 1 con số dùng để qui định mức thục lề. Mỗi lần dò xuống 1 cấp thì con số đó thay đổi, để cấp con khi được in ra sẽ có một số khoảng trắng phía trước dựa vào con số đó.

 

          Ứng dụng còn chức năng “Liệt kê các RadioMenuItem đang ở trạng thái được chọn”. Từ góc nhìn người viết ứng dụng, chúng ta nhận xét sẽ thấy đây chung quy là vấn đề duyệt đệ qui như phương thức Show. Để tách bạch trong chức năng, thì tôi thiết kế lớp Menu, cung cấp cho lập trình viên một phương thức để duyệt đệ qui vào các cấp trong menu. Tôi đặt tên phương thức là RecursiveIterator. Phương thức này nhận tham số là một hàm xử lý cho một MenuItem khi duyệt tới.

Sau đó, tôi đóng vai người lập trình sử dụng phương thức RecursiveIterator để duyệt qua các cấp, nếu tìm thấy RadioMenuItem thì sẽ xét thêm điều kiện được select hay chưa. Nếu đã select thì sẽ cho hiển thị. RecursiveIterator giống như một cổng giao tiếp với các thành phần bên trong lớp Menu.

clip_image005

          Class Diagram:

 

 

clip_image007

 

          Sau đây là code một số phương thức quan trọng/ phức tạp. Kèm theo là một số comment ghi chú kỹ thuật

 

//Hiển thị MenuItem thông qua ostream
//numberOfTabsBefore dùng để qui định định dạng phân cấp, mặc định là =0
void MenuItem::Show(ostream& os, int numberOfTabsBefore) const
{
	for (int i = 0; i < numberOfTabsBefore; i++)
	{
		os << "   ";
	}
	os << label << endl;
}

//Hiển thị Menu
//cú pháp ranged-base loop của C++ 11 làm đoạn for nhìn sáng sủa hơn.
void Menu::Show(ostream& os, int numberOfTabsBefore) const
{
	MenuItem::Show(os, numberOfTabsBefore);
	for(MenuItem* item : this->subItems)
	{
		item->Show(os, numberOfTabsBefore + 1);
	}
}

//Duyệt đệ qui
//Sử dụng toán tử typeid để so sánh kiểu dữ liệu có kế thừa. Trình dịch cần có RTTI để thực thi.
//kiểu function là 1 generic wrapper để dễ dàng gọi một function, lamda expr, bind expr,..
void Menu::RecursiveIteration(std::function<void(MenuItem*)> fun)
{
	for(MenuItem* item : this->subItems)
	{
		fun(item);
		if(typeid(*item) == typeid(Menu)) 
		{
			((Menu*)item)->RecursiveIteration(fun);
		}
	}
}

//khởi tạo Menu căn bản
//sử dụng con trỏ cấp phát động để sau khi ra khỏi hàm thì các đối tượng vẫn không bị mất đi. Chỉ cần chú ý giải phóng toàn bộ trong phương thức hủy của lớp App 
void App::Initialize()
{
	this->pMenu = new Menu("Menu/1");

	this->pMenu->Add(new RadioMenuItem("Radio/T/1.1", true));
	this->pMenu->Add(new RadioMenuItem("Radio/F/1.2", false));
	this->pMenu->Add(new MenuItem("MenuItem/1.3"));
	
	Menu* subMenu4 = new Menu("Menu/1.4");
	subMenu4->Add(new MenuItem("MenuItem/1.4.1"));
	subMenu4->Add(new RadioMenuItem("Radio/T/1.4.2", true));
	subMenu4->Add(new RadioMenuItem("Radio/T/1.4.3", true));
	
	Menu* subMenu44 = new Menu("Menu/1.4.4");
	subMenu44->Add(new MenuItem("MenuItem/1.4.4.1"));
	subMenu44->Add(new MenuItem("MenuItem/1.4.4.2"));
	subMenu4->Add(subMenu44);

	Menu* subMenu45 = new Menu("Menu/1.4.5");
	subMenu4->Add(new RadioMenuItem("Radio/T/1.4.5.1", true));
	subMenu4->Add(new RadioMenuItem("Radio/T/1.4.5.2", true));
	subMenu4->Add(subMenu45);

	this->pMenu->Add(subMenu4);

	Menu* subMenu5 = new Menu("Menu/1.5");
	subMenu5->Add(new MenuItem("MenuItem/1.5.1"));
	this->pMenu->Add(subMenu5);

}

//Liệt kê các radioMenuItem đang được select
//Truyền vào RecursiveIteration một lamda expr. Trong menu, bắt đầu duyệt qua các phần tử, các cấp, và mỗi lần đến một phần tử thì gọi các câu lệnh trong lamda expr
void App::ShowSelectedRadioMenuItem()
{
	this->pMenu->RecursiveIteration(
		[](MenuItem* item) 
		{ 
			if(typeid(*item) == typeid(RadioMenuItem) && ((RadioMenuItem*)item)->IsSelected())
			{
				item->Show(cout);
			}
		}
	);
}

 

 

3 responses to “Lập trình hướng đối tượng – Bài tập – Quan hệ hợp thành dạng đệ qui

  1. Xin chào Khang!.. Mình là học viên khóa 2009!.. mình cần sự trợ giúp 1 chút !.. nếu ban có tg rảnh!.. hãy đọc comment!..Có tài liệu nào trực quan hơn về hướng đối tượng của thầy Quang và cách ra đề như thế nào!..Mình còn mỗi môn này là “go out”!..Vì 1 một lý do nhất định nên mình tìm blog của bạn để contact riêng!.. xin cảm ơn!.. email: toancaureal.scbank@gmail.com

    Số lượt thích

    • Xin chào, mình không có tài liệu nào trực quan hơn. lúc trước đi học là chép bài và đọc ebook thôi. Đề thi của thầy tương đối đa dạng. Thi thực hành xoay quanh vấn đề quan hệ (bài toán thuận) & kế thừa đơn. Còn thi lý thuyết thì có các loại câu hỏi:
      – Tìm chỗ bất hợp lý trong thiết kế OOP, đề xuất cách sửa
      – Vẽ sơ đồ từ mô tả hoặc ngược lại cho sơ đồ rồi mô tả lại
      – Thiết kế cho 1 bài toán, 1 tình huống có sử dụng OOP, sau đó viết các hàm hành vi, xử lý, query, tính toán.
      – Đề xuất giải pháp cho 1 số trường hợp đặc biệt (lớp vô sinh, lớp chỉ tạo 1 đối tượng duy nhất, ..)
      Đề thầy hay cho sẵn hoặc giả định cho sẵn 1 số class thông dụng: string, array, time, list, … để sử dụng mà không cần cài đặt. Cần lưu ý đọc cách sử dụng thật kĩ trước khi làm bài.
      Sau khi tự hiểu và làm được tất cả các bài tập trong lớp của thầy, luyện giải 1 số đề thi các năm, đọc thêm 1 số Design Pattern. Chung qui là muốn thực sự qua môn này phải đầu tư thời gian nhiều vào design & coding oop.
      Đó là 1 vài ý kiến chủ quan…

      Số lượt thích

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Đăng xuất /  Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Đăng xuất /  Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Đăng xuất /  Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Đăng xuất /  Thay đổi )

Connecting to %s