策略模式还有个别名叫政策模式(Policy),属对象行为型模式。
意图:[b]定义一系列算法,把它们一个个封闭起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化[/b]
动机:把算法硬编写在使用他们的类中是不合适的。
不合适的地方有:
[list]
[*]代码乱
[*]多余的引用
[*]修改困难
[*]不好测试
[/list]
适用性:
[list]
[*]许多相关的类仅仅是行为不同
[*]需要使用一个算法的不同变体
[*]一个类定义了多种行为,并且这些行为在操作用以多个条件语句的形式出现。
[/list]
结构:
[img]http://dl.iteye.com/upload/attachment/166526/0e1da56d-1953-32c6-a2e7-0df728287ded.png[/img]
在动态语言里边(如Ruby),可以没有父类,用Proc和代码块可以简单实现策略模式
如:
在Ruby中还有很多轻量级策略对象,像 sort map select each 等。
效果:
[list]
[*]使算法或行为可重用
[*]继承有助于取出这些算法的公共功能
[*]算法实现与Context分离,易切换,理解,扩展
[*]算法委托给父类,省去部分Case
[*]方便单元测试
[/list]
用该模式应注意:
[list]
[*]环境对象和策略对象的接口弄错。将完整一致的,可独立的工作移出环境对象, 然后用策略对象来代理它。
[*]注意,如果你将你的环境对象和某一个策略对象过紧耦合,而无法设计中推出第二个和第三个策略对象, 那就是误用
[*]切换时必须了解不同的Strategy
[/list]
看了上面的介绍大家可能会觉得策略模式跟前面讲到的[url=http://jim-jin.iteye.com/blog/508295]模板方法[/url]没什么区别,不就都是将算法封装吗?下面讲下他们的区别:
[list]
[*]策略模式用组合,模版模式用继承,说白了就是一个封装一组算法(多算法),一个封装一个算法(单算法)。
[*]模版模式就是算法在父类中,子类不会完全改写算法,可以改写部分,或称关键部分,但整体的算法不变,可以节省大量代码
[*]策略侧重不同的行为的改变在统一的接口下,强调多态下面行为的执行过程,处理过程,可以从用户那里接受参数,只要用户提供的策略符合接口
[*]策略模式所有的算法均在子类中完成,强调行为即算法的不同,可以使程序更灵活,而模版模式中子类不能改变父类算法结构.
[/list]
下面是一个例子:
[url=http://dl.iteye.com/topics/download/c9d59dc3-0123-35ef-8992-85012739607a]源码文件点击下载[/url]
类图:
[img]http://dl.iteye.com/upload/attachment/166619/5be08893-aeb6-37a1-aaef-c4ddbc3e2f84.jpg[/img]
意图:[b]定义一系列算法,把它们一个个封闭起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化[/b]
动机:把算法硬编写在使用他们的类中是不合适的。
不合适的地方有:
[list]
[*]代码乱
[*]多余的引用
[*]修改困难
[*]不好测试
[/list]
适用性:
[list]
[*]许多相关的类仅仅是行为不同
[*]需要使用一个算法的不同变体
[*]一个类定义了多种行为,并且这些行为在操作用以多个条件语句的形式出现。
[/list]
结构:
[img]http://dl.iteye.com/upload/attachment/166526/0e1da56d-1953-32c6-a2e7-0df728287ded.png[/img]
在动态语言里边(如Ruby),可以没有父类,用Proc和代码块可以简单实现策略模式
如:
hello = lambda {
puts "I am a proc"
}
hello.call
def run_it
puts "before"
yield
puts "after"
end
run_it do
puts "I am a yield"
end
在Ruby中还有很多轻量级策略对象,像 sort map select each 等。
效果:
[list]
[*]使算法或行为可重用
[*]继承有助于取出这些算法的公共功能
[*]算法实现与Context分离,易切换,理解,扩展
[*]算法委托给父类,省去部分Case
[*]方便单元测试
[/list]
用该模式应注意:
[list]
[*]环境对象和策略对象的接口弄错。将完整一致的,可独立的工作移出环境对象, 然后用策略对象来代理它。
[*]注意,如果你将你的环境对象和某一个策略对象过紧耦合,而无法设计中推出第二个和第三个策略对象, 那就是误用
[*]切换时必须了解不同的Strategy
[/list]
看了上面的介绍大家可能会觉得策略模式跟前面讲到的[url=http://jim-jin.iteye.com/blog/508295]模板方法[/url]没什么区别,不就都是将算法封装吗?下面讲下他们的区别:
[list]
[*]策略模式用组合,模版模式用继承,说白了就是一个封装一组算法(多算法),一个封装一个算法(单算法)。
[*]模版模式就是算法在父类中,子类不会完全改写算法,可以改写部分,或称关键部分,但整体的算法不变,可以节省大量代码
[*]策略侧重不同的行为的改变在统一的接口下,强调多态下面行为的执行过程,处理过程,可以从用户那里接受参数,只要用户提供的策略符合接口
[*]策略模式所有的算法均在子类中完成,强调行为即算法的不同,可以使程序更灵活,而模版模式中子类不能改变父类算法结构.
[/list]
下面是一个例子:
class Hero
def kill(bug, skill)
skill.do(bug)
end
end
# 技能
class Skill
def do(bug="bug")
raise "This is abstract method"
end
end
# 雷电
class Thunder < Skill
def do(bug="bug")
puts '延迟3秒'
puts '闪电2下'
puts '连续的打雷'
puts "#{bug} 减血1000"
end
end
# 地震
class Earthquake < Skill
def do(bug)
puts "#{bug} 减血500"
puts '连续的地震波2秒'
puts "#{bug} 眩晕5秒"
end
end
# 旋风
class Whirlwind < Skill
def do(bug)
puts '范围100 旋风5秒并移动'
puts "#{bug} 连续减血150/每秒 "
end
end
puts "\r\n"
puts '打猪'
puts "------------"
Hero.new.kill('小猪', Thunder.new)
puts "\r\n"
puts '打小白'
puts "------------"
Hero.new.kill('小白', Earthquake.new)
puts "\r\n"
puts '打牛'
puts "------------"
Hero.new.kill('大牛', Whirlwind.new)
[url=http://dl.iteye.com/topics/download/c9d59dc3-0123-35ef-8992-85012739607a]源码文件点击下载[/url]
类图:
[img]http://dl.iteye.com/upload/attachment/166619/5be08893-aeb6-37a1-aaef-c4ddbc3e2f84.jpg[/img]