一、策略模式——经典的“鸭子”行为问题
1、定义:策略模式定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户
涉及设计原则:
- 针对接口编程,而不是针对实现编程
- 找代码中变化的地方并把他们独立出来与不变的代码区分开
核心:运用类的多态性 实现了超类引用对其所有子类的管理(向上转型) 而子类的动作则是专门有行为接口去规定 子类的具体行为由动作接口实现去描述 最后超类和接口进行"组合" 实现了各个子类动作的真正区分
下面图片 均来自headfirst 设计模式一书 源码自己写的
鸭子游戏问题:
模拟鸭子活动,有各种鸭子 会游泳、会飞、会叫
图解:
选择鸭子作为一个超类 所有的鸭子都必须继承它
但是这样会导致各种各样的问题
- 有的鸭子不会飞
- 有的鸭子不会叫
所以我们不能一味的继承 而是需要另一种方法 去实现
从上面我们知道了 鸭子都能游泳 但是有的鸭子却不会叫,有的鸭子能飞!所以我们需要在鸭子的超类上保留游泳动作,而会叫和能飞这两个动作就被提取出去了 但是接下来又该怎么办呢?
解决:
将超类的飞 和叫 两个动作提取出去 当做接口使用 面向接口化编程 即把 fly 和 quack 不确定的方法抽取出去 封装在 一个飞动作接口 和 叫动作接口 下面是具体实现
整合鸭子的行为 所有的动作接口变量都在超类duck中 由超类控制公共方法 实现类某个方法实现接口变量 下面是具体做法
具体代码:
* @description 超类
**/
public abstract class Duck {
public FlyBehavior flyBehavior;
public QuckBehavior quckBehavior;
public void quck(){
quckBehavior.quck();
}
public void fly(){
flyBehavior.fly();
}
public void swimming(){
System.out.println("鸭子都会游泳!");
}
}
"飞"行为接口
public interface FlyBehavior {
/**
* 飞
*/
void fly();
}
"叫"行为接口
public interface QuckBehavior {
/**
* 叫
*/
void quck();
}
会飞鸭子动作具体实现
public class CanFlyImpl implements FlyBehavior {
@Override
public void fly() {
System.out.println("这只鸭子会飞");
}
}
会叫鸭子动作具体实现
public class CanQuckImpl implements QuckBehavior {
@Override
public void quck() {
System.out.println("这只鸭子会叫");
}
}
不会飞鸭子动作具体实现
public class NoWayFlyImpl implements FlyBehavior {
@Override
public void fly() {
System.out.println("这只鸭子不会飞");
}
}
不会叫鸭子动作具体实现
public class NoWayQuckImpl implements QuckBehavior {
@Override
public void quck() {
System.out.println("这只鸭子不会叫");
}
}
会飞的鸭子实体类
* @description 会飞的鸭子
**/
public class CanFlyDuck extends Duck {
public CanFlyDuck() {
//具体实现动作接口
this.flyBehavior = new CanFlyImpl();
this.quckBehavior = new NoWayQuckImpl();
}
public void display(){
System.out.println("会飞的鸭子却不会叫");
}
}
会叫的鸭子实体类
* @description 会叫的鸭子
**/
public class CanQuckDuck extends Duck {
public CanQuckDuck() {
//具体实现动作接口
this.flyBehavior = new CanFlyImpl();
this.quckBehavior = new NoWayQuckImpl();
}
public void display(){
System.out.println("会飞的鸭子却不会叫");
}
}
测试:
/**
* 策略模式
*/
Duck duck = new CanFlyDuck();
((CanFlyDuck) duck).display();
duck.fly();
duck.quck();
Duck duck1 = new CanQuckDuck();
((CanQuckDuck) duck1).display();
duck1.quck();
duck1.fly();