Last active
August 29, 2015 14:16
-
-
Save geckofu/c09f1f21400c2caf3e71 to your computer and use it in GitHub Desktop.
composite pattern
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# use the Composite pattern when you are trying to build a hierarchy | |
# three moving parts: base class/interface (component), leaf classes, composite classes | |
class Task | |
attr_reader :name | |
def initialize(name) | |
@name = name | |
end | |
def get_time_required | |
0.0 | |
end | |
end | |
class CompositeTask < Task | |
def initialize(name) | |
super(name) | |
@sub_tasks = [] | |
end | |
def add_sub_task(task) | |
@sub_tasks << task | |
end | |
alias_method :<<, :add_sub_task | |
def remove_sub_task(task) | |
@sub_tasks.delete(task) | |
end | |
def get_time_required | |
@sub_tasks.inject(0) do |task, time| | |
time + task.get_time_required | |
end | |
end | |
end | |
class AddDryIngredientsTask < Task | |
def initialize | |
super("Add dry ingredients") | |
end | |
def get_time_required | |
1.0 | |
end | |
end | |
class MakeBatterTask < CompositeTask | |
def initialize | |
super('Make batter') | |
add_sub_task( AddDryIngredientsTask.new ) | |
add_sub_task( AddLiquidTask.new ) | |
add_sub_task( MixTask.new ) | |
end | |
end | |
# traverse the tree from leaves to the root: | |
# add a parent reference | |
class Task | |
def initialize(name) | |
*** | |
@parent = nil | |
end | |
end | |
class CompositeTask < Task | |
def add_sub_task(task) | |
@sub_tasks << task | |
task.parent = self | |
end | |
def remove_sub_task(task) | |
@sub_tasks.delete(task) | |
task.parent = nil | |
end | |
end | |
# get the ultimate parent | |
while task | |
task = task.parent | |
end | |
# the usual error of Composite Pattern is that assuming all of the child components | |
# are leaf objects and not other composites. | |
# the right way to handle this situation is to define total_num_of_tasks method in the | |
# component class: | |
class Task | |
def total_num_of_tasks | |
1 | |
end | |
end | |
class CompositeTask < Task | |
def total_num_of_tasks | |
@sub_tasks.inject(0) do |task, sum| | |
sum + task.total_num_of_tasks | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment