回顾上面的例子:
1、我们使用继承的方法,结果因为鸭子的行为在子类中会不断的变化,为勒适应这种变化,我们不得不一遍遍的在子类中覆盖父类的方法,结果导致勒代码的大量重复。
2、然后,我们使用了接口的方法,结果仍然不行,因为接口实现,无法做到代码的重复利用,这在一个可扩展的程序中,显然是不号的。
3、然后,我们使用了策略者模式,将变化的部分,独立出来,转换为两组策略,fly策略组和quake策略组。然后采用组合的方式,使得同种策略的不同实现可以相互的替换,解决了代码的重复和不可重利用的缺点。
一、策略者模式的定义:
The Strategy Pattern defines a family of algorithms,encapsulates each one,and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.(策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。)
二、策略者模式的设计原则:
1、将变化的部分独立出来,定义一系列变化的实现,并将每一个封装起来,并可以相互替换。
2、针对接口编程,而不是针对实现编程。针对接口编程,并不是侠义上的java的interface,而是“针对超类型”编程。
3、多用组合,少用继承。
Favor composition over inheritance.(优先使用对象组合,而非类继承)
关于组合和继承,我们只要这样来理解即可:组合是一种“ HAS-A ”关系,而继承是一种“ IS-A ”关系。很明显“ HAS-A ”要比“ IS-A ”更灵活一些。也就是说在创建系统的时候,我们应该优先使用对象组合,因为它不仅可以给你提供更多灵活性和扩展性,而且还使你可以在运行时改变行为 ( 组合不同的对象 ) ,这简直是酷毙了!但是也不是说继承就是不能用,只是说应该把继承应用在相对更稳定,几乎没有变化的地方,例如前面的 Duck 类里的 Swim() 方法,因为可以肯定所有鸭子一定都会游泳,所以就没有必要给这个行为提供基于 Strategy 模式的实现方式,因为那样做除了是程序更复杂以外,没有什么意义。
三、应用场景和优缺点:
上面我们已经看过了Strategy模式的详细介绍,下面我们再来简单说说这个模式的优缺点吧!怎么说呢,人无完人,设计模式也不是万能的,每一个模式都有它的使命,也就是说只有在特定的场景下才能发挥其功效。我们要使用好模式,就必须熟知各个模式的应用场景。
对于Strategy模式来说,主要有这些应用场景:
1、 多个类只区别在表现行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为。(例如FlyBehavior和QuackBehavior)
2、 需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其它方式来实现。(例如FlyBehavior和QuackBehavior的具体实现可任意变化或扩充)
3、 对客户(Duck)隐藏具体策略(算法)的实现细节,彼此完全独立。
对于Strategy模式来说,主要有如下优点:
1、 提供了一种替代继承的方法,而且既保持了继承的优点(代码重用)还比继承更灵活(算法独立,可以任意扩展)。
2、 避免程序中使用多重条件转移语句,使系统更灵活,并易于扩展。
3、 遵守大部分GRASP原则和常用设计原则,高内聚、低偶合。
对于Strategy模式来说,主要有如下缺点:
1、 因为每个具体策略类都会产生一个新类,所以会增加系统需要维护的类的数量。
四、策略模式组成:
1、抽象策略角色:策略类,通常由一个接口或者抽象类实现
2、具体策略角色:包括了相关的算法和行为,可能不止一个具体策略角色
3、环境角色:持有一个策略类的引用,最终给客户端调用的。
五、策略模式编写的步骤:
1、对一组算法抽象出一个共同接口,定义这个共同接口
2、编写策略类,实现这个借口,每个策略类都有其独特的实现
3、编写环境角色类,类中持有一个对共同接口的引用,对策略对象注入如set方法和get方法或者用构造方法完成赋值