本系列文章中涉及到代码大部分为《Head First设计模式》书中代码,测试可以成功运行
策略模式的定义:定义算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
定义分析: 将算法封装起来,算法间可以互相替换且独立于客户,说明各个算法有相同的特性,也就是实现了同一个超类接口,为了和客户解耦,让客户持有超类,运行时动态选择算法,也就是多态。
使用场景: (百度百科)
1、 多个类只区别在表现行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为。
2、 需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其它方式来实现。
3、 对客户隐藏具体策略(算法)的实现细节,彼此完全独立。
UML类图
Context:持有Strategy的一个引用
Strategy:抽象策略角色,一般为接口或抽象类,为具体的策略角色提供所需的接口
ConcreteStrategy:具体策略角色,实现了相应的算法
策略角色的一个例子
抽象环境角色
public abstract class Duck {
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;
public abstract void display();
public void performFly(){
flyBehavior.fly();
}
public void performQuack(){
quackBehavior.quack();
}
public void setFlyBehavior(FlyBehavior flyBehavior) {
this.flyBehavior = flyBehavior;
}
public void setQuackBehavior(QuackBehavior quackBehavior) {
this.quackBehavior = quackBehavior;
}
}
抽象策略角色
public interface FlyBehavior{
public void fly();
}
public interface QuackBehavior{
public void quack();
}
具体策略角色
public class FlyWithWings implements FlyBehavior{
@Override
public void fly(){
System.out.println("flying");
}
}
public class FlyNoWays implements FlyBehavior{
@Override
public void fly(){
System.out.println("I can't fly");
}
}
public class FlyRocketPowered implements FlyBehavior {
@Override
public void fly() {
System.out.println("fly with a rocket");
}
}
public class Quack implements QuackBehavior{
@Override
public void quack(){
System.out.println("Quack");
}
}
public class MuteQuack implements QuackBehavior{
@Override
public void quack(){
System.out.println("silence");
}
}
public class Squeak implements QuackBehavior{
@Override
public void quack(){
System.out.println("squeak");
}
}
具体环境角色
public class MallardDuck extends Duck {
public MallardDuck() {
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
@Override
public void display() {
System.out.println("-----MallardDuck-----");
}
}
public class ModelDuck extends Duck {
public ModelDuck() {
flyBehavior = new FlyNoWays();
quackBehavior = new Quack();
}
@Override
public void display() {
System.out.println("-----modelDuck-----");
}
}
测试
public class Teat {
public static void main(String[] args) {
Duck mallardDuck = new MallardDuck();
mallardDuck.display();
mallardDuck.performFly();
mallardDuck.performQuack();
Duck modelDuck = new ModelDuck();
modelDuck.display();
modelDuck.performFly();
modelDuck.setFlyBehavior(new FlyRocketPowered());
mallardDuck.performFly();
modelDuck.performQuack();
}
}
结果
设计原则
文中设计到几个设计原则,在这里介绍一下
- 封装变化
把代码中会变化的部分提取出来并封装,好让其他部分不受影响,使由代码变化引起的不经意后果变少,系统变得更加有弹性 - 多用组合,少用继承
像示例中鸭子类中结合了飞行和鸣叫两个类的行为就是组合,使用组合使得系统具有很大的弹性,不仅仅可以将算法族封装成类,更可以“在运行时动态地改变行为” - 针对接口编程,不针对实现编程
利用接口代表每个行为,行为的每一个实现都实现一个接口,我们称这些类为”行为“类,与以往不同的是,行为不再来自与超类的某个具体实现或继承某个接口并由子类自行实现而来的这些高耦合的方式,在示例里,鸭子的子类使用接口表示的行为,所以实际的行为不会被绑死在类中,并且也不需要知道行为的具体实现细节