问题
Does anyone have a good example in Ruby of using a Composite of Commands? It is a design pattern hybrid that I have seen mentioned in various Design Patterns literature which sounds quite powerful, but have not been able to find any interesting use cases or code.
回答1:
Inspired by the general idea and the sample pattern implementations in this blog post, here's a stab at what it might look like:
class CompositeCommand
def initialize(description, command, undo)
@description=description; @command=command; @undo=undo
@children = []
end
def add_child(child); @children << child; self; end
def execute
@command.call() if @command && @command.is_a?(Proc)
@children.each {|child| child.execute}
end
def undo
@children.reverse.each {|child| child.undo}
@undo.call() if @undo && @undo.is_a?(Proc)
end
end
And sample usage using the application of a software installer program:
class CreateFiles < CompositeCommand
def initialize(name)
cmd = Proc.new { puts "OK: #{name} files created" }
undo = Proc.new { puts "OK: #{name} files removed" }
super("Creating #{name} Files", cmd, undo)
end
end
class SoftwareInstaller
def initialize; @commands=[]; end
def add_command(cmd); @commands << cmd; self; end
def install; @commands.each(&:execute); self; end
def uninstall; @commands.reverse.each(&:undo); self end
end
installer = SoftwareInstaller.new
installer.add_command(
CreateFiles.new('Binary').add_child(
CreateFiles.new('Library')).add_child(
CreateFiles.new('Executable')))
installer.add_command(
CreateFiles.new('Settings').add_child(
CreateFiles.new('Configuration')).add_child(
CreateFiles.new('Preferences')).add_child(
CreateFiles.new('Help')))
installer.install # => Runs all commands recursively
installer.uninstall
回答2:
I'm trying to understand this pattern myself, and have been mulling over what things might be modeled this way.
The basic idea of the Composite pattern is situations where items and collections need to be treated, in some respects, the same way. Collections may contain a mixture of items and subcollections, nested as deeply as you like.
Some ideas I have (borrowing some from Design Patterns in Ruby and Ruby Under a Microscope):
A filesystem
You can ask a file for its size, and it returns a simple value. You can also ask a folder for its size, and it return the sum of the sizes of its files and subfolder. The subfolders are of course returning the sum of their files and subfolders.
Likewise, both files and folders can be moved, renamed, deleted, backed up, compressed, etc.
A system command
A command object could have a run
method. That method could work by running any number of subcommands, which have subcommands, etc. It could return true if all of its subcommands return true, and could report statistics based on its childrens' statistics (time elapsed, files modified, etc).
A company hierarchy
Individuals, teams, divisions, and whole companies could all be seen as having salaries, bringing in revenue, completing units of work, etc.
A military unit
In a game, a soldier could have defense and offense statistics, could be told to move to a location, attack a base, etc. Regiments and divisions could be treated the same way.
Weight or monetary value
The weight of a truck full of boxes includes the weight of each box. The weight of each box includes the weight of each of its items, their parts, etc.
Similarly, the monetary value of a financial portfolio is the value of all its assets. Some of those assets might be index funds that contain multiple stocks. You could buy or sell an individual stock or an entire portfolio.
GUI elements
A window could be composed of frames, which are composed of frames, which are composed of frames. Any element can be positioned, shaded, focused, hidden, etc.
Expressions in a programming language
When the Ruby interpreter evaluates an expression, it does so by breaking it down into a tree of expressions (an Abstract Syntax Tree) and evaluating each of those, coming to the final value by working its way back to the top of the tree. In a sense, each level of the tree is asked the same question: "what is your value?"
As a simple example, the first step in finding the value of ((4 + 8) * 2)) + 9
is to find the value of 4 + 8
.
来源:https://stackoverflow.com/questions/10560892/composite-of-commands-design-pattern