Báo cáo cuối kỳ môn Lập trình hướng đối tượng - Chủ đề: Strategy Pattern - Nguyễn Hoàng Thức

ĐẠI HỌC QUỐC GIA THÀNH PHỐ HỒ CHÍ MINH  
TRƯỜNG ĐẠI HỌC KHOA HỌC TỰ NHIÊN  
Khoa Công nghệ Thông tin  
BÁO CÁO CUỐI KÌ  
Môn: Lập trình hướng đối tượng  
Chủ đề: Strategy Pattern  
Nhóm: 3  
Sinh viên thực hiện :  
1760438 : Nguyễn Hoàng Thức  
1760311 : Hoàng Minh Hiếu  
1760479 : Phạm Hữu Tài  
1760332 : Nguyễn Quốc Khánh  
TP.HCM, ngày 25 tháng 11 năm 2018  
Mục lục  
i.  
ii.  
iii.  
i.  
ii.  
I. Bài toán sử dụng Strategy Pattern  
Bài toán:  
Giả sử chúng ta sẽ xây dựng một game tên là Street Fighter. Game sẽ có các nhân vật  
(Character). Mỗi nhân vật có 4 kĩ năng là đá (kick), đấm (punch), lăn (roll) và nhảy (jump). Mỗi  
nhân vật đều có 2 kĩ năng cơ bản là punch() và roll(), còn 2 kĩ năng còn lại là kick() và jump()  
thì sẽ phụ thuộc vào mỗi nhân vật. Ngoài ra, 2 kĩ năng đó còn có nhiều cách thực hiện.  
Hãy xây dựng các lớp trên bằng phương pháp lập trình hướng đối tượng bằng ý tưởng sử dụng  
kế thừa và đa hình.  
II. Cách giải bài toán nếu không sử dụng pattern  
Vài toán này, ta dùng tính kế thừa (Inheritance) để xây dựng các lớp.  
Ta gọi class Fighter là class tổng quát của game. Lớp Fighter sẽ có những default  
implementation của các hành động. Mỗi nhân vật nếu có những hành động đặc biệt đều có thể  
override lại các actions cơ bản. Ví dụ LeeSin có thể override lại method Kick() bằng  
DragonKick() (Nộ long cước).  
Do đó ta có sơ đồ UML sử dụng đa hình như sau :  
   
Fighter class  
+ Display(): void  
+ Kick(): void  
+ Punch(): void  
+ Jump: void  
+ Roll: void  
LeeSin  
Garen  
Gragas  
+ Display(): void  
+ Kick(): void  
+ Display(): void  
+ Kick(): void  
+ Display(): void  
+ Kick(): void  
+ Punch(): void  
+ Jump: void  
+ Punch(): void  
+ Roll: void  
+ Punch(): void  
+ ShortJump: void  
+ Roll(): void  
+ LongJump():void  
+ LightningKick(): void  
Theo UML trên, ta có các class con kế thừa đủ các action cơ bản.  
Trong trường hợp nhân vật nào không có những action đặc biệt, ta sẽ override nó thành một  
method rỗng. Ví dụ Garen không có action Roll, do đó ta sẽ implement lại method Roll() bằng  
cách override lại.  
cl ass Gar en : publ i c Fi ght er  
{
publ i c:  
voi d Ki ck( ) {  
}
} ;  
Như vậy, cơ bản lớp Fighter đã được hoàn thành, và có thể chạy được.  
WithoutStrategy.cp  
p
Source code đính kèm (nhấn đúp để mở):  
III. Nhược điểm của cách giải ở trên  
Theo cách làm trên, chuyện gì sẽ xảy ra nếu như có 1 nhân vật nào đó không có hành động  
đặc biệt, như Roll() (lăn) chả hạn?  
Mặc dù chúng ta có thể override hành động Roll() thành một method rỗng như hình trên,  
nhưng giả sử nếu game có tới bao nhiêu nhân vật tương tự như vậy, ta phải override lại  
method Roll() bấy nhiêu lần, chưa kể nếu sau này game có thể ra thêm nhiều nhân vật khác  
 
cũng không có hành động Roll(). Nếu như ta quên không override, các kĩ năng sẽ bị leak và các  
nhân vật sẽ có đầy đủ các kĩ năng như bình thường.  
Do đó, sử dụng kế thừa (Inheritance) cho bài toán này sẽ gây khó khăn cho việc maintain cũng  
như là develop.  
IV. Giới thiệu về Strategy Pattern  
Khái niệm:  
Strategy Pattern (thuộc nhóm Behavior Pattern) là một mẫu thiết kế cho phép phương thức của  
đối tượng được chọn khi chạy chương trình.  
Mục đích  
Định nghĩa và bao bọc các thuật toán có cùng mục đích trong những lớp có giao diện chung.  
Làm cho sự thay đổi thuật toán trở lên linh động và độc lập với khách hàng, cho phép giải thuật  
tùy biến độc lập tại Client sử dụng nó.  
Strategy thường được sử dụng để thay thế cho sự kế thừa, khi bạn muốn chấm dứt việc theo  
dõi và chỉnh sửa 1 chức năng qua nhiều lớp con.  
Trường hợp nào nên sử dụng Strategy Pattern?  
Đoạn code dễ thay đổi và muốn tách chúng ra khỏi chương trình chính để dễ dàng chỉnh sửa,  
bảo trì.  
Tránh sự rắc rối khi phải hiện thực một chức năng nào đó qua quá nhiều lớp con.  
Muốn thay đổi thuật toán sử dụng khi chạy chương trình.  
V. Cách giải bài toán trên nếu sử dụng pattern  
Pattern ta sử dụng để giải quyết bài toán này sẽ là Strategy.  
Các bước thực hiện ý tưởng và xây dựng các class:  
Bước đầu tiên ta sẽ nhận diện các hành động nào có thể được tái sử dụng và có nhiều biến thể,  
phân tách nó thành những class riêng biệt.  
Ở đây các hành động đó là Kick() va Jump(). Ta đưa 2 method ra khỏi class Fighter và tạo mỗi  
class đại diện cho mỗi hành động.  
Class diagram hoàn chỉnh:  
         
KickBehavior  
Kick(): void  
Fighter  
- Kick behavior: KickBehavior  
- JumpBehavior: JumpBehavior  
LightningKick  
Kick(): void  
DragonKick  
Kick(): void  
+ Display(): void  
+ Kick(): void  
+Jump(): void  
+ Punch(): void  
+ setKickBehavior(): void  
+ setJumpBehavior(): void  
JumpBehavior  
Jump(): void  
LongJump  
ShortJump  
Jump(): void  
Jump(): void  
LeeSin  
Gragas  
Garen  
+ Display(): void  
+ Kick(): void  
+ Punch(): void  
+ Roll: void  
+ Display(): void  
+ Kick(): void  
+ Punch(): void  
+ Jump: void  
+ Display(): void  
+ Punch(): void  
+Jump(): void  
Như vậy source code cho bài toán này với ý tưởng dùng Strategy ở đây:  
UsingStrategy.cpp  
Nhận xét : Sử dụng Strategy pattern cho bài toán này giúp ta dễ dàng maintain từ class cao  
đến thấp. Giả sử như nếu có một kĩ năng mới tên là BackKick, ta chỉ đơn giản implement  
BackKick class kế thừa KickBehavior, rồi setKickBehavior thành BackKick cho nhân vật.  
Với những nhân vật không có kĩ năng kick, ta cũng đơn giản tạo 1 class DisableKick kế thừa  
KickBehavior, rồi setKickBehavior cho những nhân vật đó.  
Và hơn thế, ta có thể cất giữ 2 kĩ năng Kick và Jump với private access , giúp các nhân vật tạo  
ra không đơn giản kế thừa được những kĩ năng này. Mà do chính chúng ta sẽ quyết định nhân  
vật tạo ra có quyền thực hiện kiểu kick, kiểu jump nào hoặc không có cả 2 kĩ năng.  
VI. Một số bài toán khác có thể giải bằng Strategy Pattern  
Ví dụ: 1. Trong nông trại có nhiều vật nuôi, mỗi vật nuôi có những  
phương thức ăn cỏ, cho sữa, sinh con khác nhau. Cài đặt phương thức đó cho class Giasuc để  
chúng thực hiện đúng với mỗi loài.  
2. Các phương tiện di chuyển như xe đạp, máy bay, xe hơi, tàu ngầm…  
có phương thức “go” khác nhau. Cài đặt chương trình để con người sử dụng phương tiện với  
phương thức “go” chính xác cho mỗi phương tiện.  
VII. Ưu và nhược điểm  
Ưu điểm:  
Một nhóm các thuật toán có thể được định nghĩa như một hệ thống phân cấp lớp và có thể  
được sử dụng thay thế cho nhau để thay đổi hành vi, ứng dụng mà không thay đổi kiến trúc  
của nó.  
Bằng cách đóng gói thuật toán một cách riêng biệt, các thuật toán mới tuân thủ cùng một giao  
diện có thể dễ dàng được giới thiệu.  
Ứng dụng có thể chuyển đổi chiến lược trong lúc chạy chương trình.  
Strategy cho phép người dùng lựa chọn thuật toán cần thiết mà không cần sử dụng câu lệnh  
“switch” hoặc một loạt câu lệnh “if - else”.  
Các cấu trúc dữ liệu được sử dụng để thực hiện thuật toán được đóng gói hoàn toàn trong các  
Strategy class. Do đó, việc thực hiện một thuật toán có thể được thay đổi mà không ảnh hưởng  
đến Context class.  
Nhược điểm :  
Các ứng dụng phải được biết tất cả các thuật toán đã cài đặt để chọn một trong những thuật  
toán trong tình huống thích hợp.  
Context và các Strategy class thường giao tiếp thông qua giao diện được chỉ định bởi abstract  
Strategy base class. Strategy base class phải trưng ra giao diện cho tất cả các hành vi cần thiết,  
mà một số lớp chiến lược cụ thể có thể không triển khai.  
Trong hầu hết các trường hợp, ứng dụng sẽ cấu hình Context với đối tượng Strategy cần thiết.  
Do đó, ứng dụng cần tạo và duy trì hai đối tượng thay cho một đối tượng.  
       
docx 6 trang myanh 25740 Free
Bạn đang xem tài liệu "Báo cáo cuối kỳ môn Lập trình hướng đối tượng - Chủ đề: Strategy Pattern - Nguyễn Hoàng Thức", để tải tài liệu gốc về máy hãy click vào nút Download ở trên

File đính kèm:

  • docxbao_cao_cuoi_ky_mon_lap_trinh_huong_doi_tuong_chu_de_strateg.docx
  • pptxDecorator.pptx
  • cppWithoutStrategy.cpp
  • cppUsingStrategy.cpp
  • cppDecorater.cpp