Design Pattern - Composite
Xây dựng phần mềm hướng đối tượng là một quá trình thu thập các object đơn giản (các object này chỉ gồm các thành phần đơn giản như integer và string), rồi kết hợp thành những object phức tạp hơn như các hồ sơ nhân sự hay danh sách các bài hát. Tuy nhiên đôi khi chúng ta lại muốn xây dựng một ...
Xây dựng phần mềm hướng đối tượng là một quá trình thu thập các object đơn giản (các object này chỉ gồm các thành phần đơn giản như integer và string), rồi kết hợp thành những object phức tạp hơn như các hồ sơ nhân sự hay danh sách các bài hát.
Tuy nhiên đôi khi chúng ta lại muốn xây dựng một object phức tạp nhưng object này lại giống hệt những thành phần mà chúng ta sử dụng để xây dựng nó. Nó giống với quy trình làm bánh (Menufacture cake) trong hình sau:
Quy trình Manufacture Cake bao gồm Make Cake và Package Cake. Make Cake và Package Cake gồm nhiều quy trình nhỏ hơn. Những quy trình này chính là các object phức tạp mà chúng ta muốn xây dựng vì những quy trình này đều giống nhau, quy trình mức cao hơn thì chứa các quy trình mức thấp hơn. Ta có thể dễ dàng implement các quy trình trên 1 interface với tên quy trình (name), thời gian hoàn thành (time) và chứa các quy trình con (subtasks).
Xây dựng Composite
GoF gọi design pattern "các hoạt động tổng thể theo các thành phần con" là Composite pattern.
Tức là, khi cần xây dựng 1 hệ thống hoặc một cây các đối tượng mà không muốn khi code phải lo lắng xem liệu nó cần phải giải quyết một đối tượng đơn lẻ hay tổng thể cả một cây đối tượng thì ta cần sử dụng tới Composite pattern
Để xây dựng Composite pattern, ta cần 3 thành phần:
-
Đầu tiên, cần một infterface chung hoặc base class cho toàn bộ các đối tượng. (nó gọi là component). Khi xây dựng component hay nghĩ tới các điểm chung giữa các đối tượng cơ bản và các đối tượng ở mức cao hơn, Giống như việc làm bánh, các task đơn giản như ước lượng bột và task phức tạp như làm bột đều tiêu tốn thời gian.
-
Thứ hai, ta cần một hoặc nhiều leaf class - là các bước không thể phân chia được nữa (là bước ước lượng bột và thêm trứng). Các leaf class nên được implement Component interface.
-
Thứ ba, ta cần ít nhất một class ở mức cao hơn, gọi là composite class. Composite chính là một component, nhưng nó là đối tượng ở mức cao hơn được build từ các subcomponent. Trong ví dụ làm bánh thì composite là những task phức tạo như làm bột hoặc quy trình làm cả chiếc bánh.
#component base class class Task attr_reader :name def initialize(name) @name = name end def get_time_required 0.0 end end
2 leaf class
class AddDryIngredientsTask < Task def initialize super('Add dry ingredients') end def get_time_required 1.0 # 1 minute to add flour and sugar end end class MixTask < Task def initialize super('Mix that batter up!') end def get_time_required 3.0 # Mix for 3 minutes end end
Task ở mức cao hơn (composite):
class MakeBatterTask < Task def initialize super('Make batter') @sub_tasks = [] add_sub_task( AddDryIngredientsTask.new ) add_sub_task( AddLiquidsTask.new ) add_sub_task( MixTask.new ) end def add_sub_task(task) @sub_tasks << task end def remove_sub_task(task) @sub_tasks.delete(task) end def get_time_required time=0.0 @sub_tasks.each {|task| time +=task.get_time_required} time end end
class MakeBatterTask chính là 1 task composite, ngoài ra chúng ta còn cần xây dựng các task composite khác như packaging the cake và manufacturing the cake. Các task này cũng giống với MakeBatterTask nhưng nó bao gồm các subclass khác nhưng xử lý trong class là tương đương. Vì thế chúng ta có thể tạo 1 base class cho những task composites
class CompositeTask < Task def initialize(name) super(name) @sub_tasks = [] end def add_sub_task(task) @sub_tasks << task end def remove_sub_task(task) @sub_tasks.delete(task) end def get_time_required time=0.0 @sub_tasks.each {|task| time += task.get_time_required} time end end class MakeBatterTask < CompositeTask def initialize super('Make batter') add_sub_task( AddDryIngredientsTask.new ) add_sub_task( AddLiquidsTask.new ) add_sub_task( MixTask.new ) end end class MakeCakeTask < CompositeTask def initialize super('Make cake') add_sub_task( MakeBatterTask.new ) add_sub_task( FillPanTask.new ) add_sub_task( BakeTask.new ) add_sub_task( FrostTask.new ) add_sub_task( LickSpoonTask.new ) end end
Tham khảo
Github (updating):https://github.com/ducnhat1989/design-patterns-in-ruby
Sách: “DESIGN PATTERNS IN RUBY” của tác giả Russ Olsen
:
- CÁC NGUYÊN TẮC TRONG DESIGN PATTERN