策略模式 :定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
比如鸭子类(祖先类) ,鸭子有很多的行为,比如叫,飞,游泳,外观。有各种类型的鸭子继承自鸭子类,如橡皮鸭,绿头鸭,诱饵鸭。 但是很多行为在不同的鸭子类中表现并不相同,比如叫这个行为就有不同,橡皮鸭吱吱叫,绿头鸭呱呱叫,诱饵鸭是不会叫的。所以可以把叫行为分装成一个算法族。有接口---“叫”。具体的行为作为类继承叫接口,实现叫行为。
package strategy; public interface QuackBehavior { void quack(); }具体行为
package strategy; public class Quack implements QuackBehavior { @Override public void quack() { // TODO Auto-generated method stub System.out.println("呱呱叫呱呱叫"); } }
package strategy; public class Squeak implements QuackBehavior { @Override public void quack() { // TODO Auto-generated method stub System.out.println("吱吱吱吱吱吱"); } }
package strategy; public class MuteQuack implements QuackBehavior { @Override public void quack() { // TODO Auto-generated method stub System.out.println("........."); } }以上作为一个算法族。
而比如游泳这个行为每种鸭子都会实现。这样我们就可以在鸭子类(祖先类)大胆的定义这个行为。而作为像 叫 这个行为如何处理呢。我们可以在祖先类中为 叫 接口申明一个引用变量,所有鸭子子类都会继承他们,比如橡皮鸭可以吱吱叫。那么在继承祖先类后我们有一个 叫 的接口引用变量,在实例化变量时我们可以选择不同的类,比如呱呱叫类或者吱吱叫类。
祖先类
package strategy; public class Duck { //接口 QuackBehavior quackBehavior; void quack(){}; void display(){}; void performQuack(){ quackBehavior.quack(); }; void swim(){ System.out.println("所有的鸭子都会游泳"); }; public void setQuackBehavior(QuackBehavior qb){ quackBehavior = qb; } }橡皮鸭
package strategy; public class ModelDuck extends Duck { public ModelDuck(){ quackBehavior = new Quack();//呱呱叫 } public void display(){ System.out.println("i am a model duck"); } }那么如果我们 叫 加一个比如说嗷嗷嗷叫。那么我们就可以加类继承 叫 接口,并填充其方法叫。这样如果有的鸭子是嗷嗷叫的话呢就可以选择在实例化自己时候选择new 嗷嗷叫类把它付给 叫 接口引用接口。易于我们进行扩展。而我们说游泳行为的话,因为所有的鸭子都会游泳所以不需要再定义一个算法族。但是如果需要的话我们也可以像 叫 一样进行一种剥离。把它从祖先类中剥离。继承的时候我们具体类可以具体分析。
动态设定行为:
在鸭子的子类中通过设定方法来设定鸭子的行为。而不是在鸭子的构造器内实例化。
比如如果我们的模型鸭子因为老化问题本来是呱呱叫。。现在变成吱吱叫了。。那怎么办呢。。。注意看祖先类中有一个改变方法
public void setQuackBehavior(QuackBehavior qb){ quackBehavior = qb; }这样我们可以随时调用这个方法改变鸭子的行为。
下面是测试:
package strategy; public class MiniDuckSimulatorTEST { public static void main(String[] args){ Duck model = new ModelDuck(); model.display(); model.performFly();
model.performQuack(); model.setQuackBehavior(new Squeak()); System.out.println("----老了变声吱吱叫了-----"); model.performQuack(); } }
控制台输出结果:
i am a model duck我不会飞
呱呱呱呱呱呱
------老了变声吱吱叫了---------
吱吱吱吱吱吱
总结:
1.面向对象设计原则
1.1 封装 变化的概念
1.2 编程中使用接口 ,而不是对接口的实现
2.策略模式的定义
2.1定义一组算法,将每个算法都封装起来,并且使它们之间可以互换 (“叫” 算法族)
2.2策略模式使这些算法在客户端调用它们的时候能够互不影响地变化
3.策略模式的意思
3.1策略模式使开发人员能够开发出由许多可替换 的部分组成的软件,并且各个部分之间是弱连接 的关系
3.2弱连接的特性使软件具有更强的可扩展性 ,易于维护 ;更重要的是,它大大提高了软件可重用性 。
4.策略模式的组成
4.1抽象策略角色 :策略类,通常由一个接口或者抽象类实现 “ 叫 ” 接口
4.2具体策略角色 :包装了相关的算法和行为 自己是实现 “ 叫
” 接口 的类 比如呱呱叫类 吱吱叫类
4.3环境角色 :既有策略类的引用,最终给客户端调用的。 ModelDuck 橡皮鸭类
5.缺点
5.1客户端必须知道所有的策略类,并自行决定使用哪个策略类。
5.2造成很多的策略类
5.3 解决办法 --使用工厂模式
一句话 工厂相当于黑盒子,策略相当于白盒子