设计原则
- 找出应用中可能需要变化之处,把它们独立出来。不要和那些不需要变化的代码混在一起
- 针对接口编程,而不是针对实现编程
- 多用组合,少用继承
定义和实现思路
定义算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
- 把算法动机使用接口抽象
- 实现算法动机的接口,实现具体算法行为
- 在使用此类算法的客户中,使用算法接口持有实例变量
- 在客户中,把算法行为委托给实例变量
- 并且可以提供setter方法,在运行时动态更改具体的算法行为
UML模型
具体代码
/**
* 接口封装行为
*
* @author luhuancheng
* @since 2018/3/25 21:56
*/
public interface FlyBehavior {
void fly();
}
/**
* 实现行为接口,封装具体行为
*
* @author luhuancheng
* @since 2018/3/25 21:57
*/
public class FlyWithWings implements FlyBehavior {
@Override
public void fly() {
System.out.println("I'm flying!");
}
}
/**
* 接口封装行为
*
* @author luhuancheng
* @since 2018/3/25 21:55
*/
public interface QuackBehavior {
void quack();
}
/**
* 实现行为接口,封装具体行为
*
* @author luhuancheng
* @since 2018/3/25 21:58
*/
public class Quack implements QuackBehavior {
@Override
public void quack() {
System.out.println("Quack!");
}
}
/**
*
*抽象超类,用实例变量组合两个接口的实现类实例
*/
public abstract class Duck {
QuackBehavior quackBehavior;
FlyBehavior flyBehavior;
/**
* 委托给具体的行为类
*/
public void performQuack() {
quackBehavior.quack();
}
/**
* 委托给具体的行为类
*/
public void performFly() {
flyBehavior.fly();
}
public abstract void display();
public void swim() {
System.out.println("Duck swim");
}
/**
* 运行时动态改变具体行为
* @param quackBehavior
*/
public void setQuackBehavior(QuackBehavior quackBehavior) {
this.quackBehavior = quackBehavior;
}
/**
* 运行时动态改变具体行为
* @param flyBehavior
*/
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
}
/**
* 将不变的代码封装在超类(Duck)中,把变化的代码用接口抽象,并且使用组合的方式把接口的具体方式引入。
* 通过委托的方式执行具体的行为
*
* @author luhuancheng
* @since 2018/3/25 22:11
*/
public class MallardDuck extends Duck {
public MallardDuck() {
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
@Override
public void display() {
System.out.println("I'm a real Mallard duck");
}
}
/**
* 客户端类
*
* @author luhuancheng
* @since 2018/3/25 22:16
*/
public class Client {
public static void main(String[] args) {
Duck mallard = new MallardDuck();
mallard.performFly();
mallard.performQuack();
}
}
调用时序图
总结
- 我们把两类算法(即QuackBehavior、FlyBehavior)抽象为接口
- 每一类算法都可以提供形态、方式各异的具体逻辑(此例的实现为QuackBehavior -> Quack;FlyBehavior -> FlyWithWings)
- 在抽象超类中(Duck)使用实例变量持有以上两类算法(即QuackBehavior、FlyBehavior),并且提供了运行时动态改变算法行为的setter方法(setQuackBehavior、setFlyBehavior)。这就实现了在客户端类中,可以调用这两个方法,按需设置实现了接口(QuackBehavior、FlyBehavior)的各种算法实现。剥离了代码中经常变化的部分
- 提供代理方法,执行算法操作(performQuack、performFly)