设计模式入门——Head First

设计模式是被前人发现、经过总结形成了一套某一类问题的一般性解决方案。使用模式最好的方式是:把模式装进脑子,然后在设计和已有的应用中,寻找何处可以使用它们。以往是代码复用,现在是经验复用。

从模拟鸭子游戏说起

初始需求:各种鸭子(野鸭MallardDuck、红头鸭RedheadDuck等),一边游泳swim,一边呱呱叫quack,每种鸭子外观都不同display。

初始方案:设计一个鸭子超类,并让各种鸭子继承此超类。

需求变更:让鸭子能够飞fly。

方案1:在Duck类中加上fly()。

结果:所有鸭子都继承fly,但并非所有鸭子都会飞,比如橡皮鸭RubberDuck(继承牵一发动全身)。

方案1_1:对于不能飞的鸭子,在子类中覆盖fly()。

结果:每当有新的鸭子出现,就要被迫检查并可能需要覆盖fly()。同理,对于叫声quack也一样。

方案2:把fly()和quack()从超类中取出,放进Flyable和Quackable接口中,只会飞的鸭子实现Flyable,会叫的实现Quackable。

 

结果:不会再有会飞的橡皮鸭,但由于接口不具有实现代码,造成代码无法复用(接口无法达到代码复用)。

方案2_1:设计两个接口FlyBehavior和QuackBehavior,还有它们对应的类,负责实现具体行为。

结果:飞行和呱呱叫动作可以被其他的对象复用,因为这些行为已经与鸭子类无关;可以新增一些行为,不会影响到既有的行为类,也不会影响使用飞行行为的鸭子类(有了继承的复用好处,没了继承所带来的包袱)。

完善方案2_1:在Duck类中加入两个变量“flyBehavior”和“quackBehavior”,声明为接口类型,用performFly和performQuack分别取代fly和quack;同时加入两个新方法setFlyBehavior和setQuackBehavior,用来随时改变鸭子的行为。

测试Duck的代码

Duck类(Duck.java)

public abstract class Duck {
    //所有鸭子子类都继承它
    FlyBehavior flyBehavior;
    QuackBehavior quackBehavior;
    public Duck(){
    }
    public abstract void display();
    
    public void perfmormFly(){
        //委托给行为类
        flyBehavior.fly();
    }
    public void performQuack(){
        //委托给行为类
        quackBehavior.quack();
    }
    public void setFlyBehavior(FlyBehavior fb){
        flyBehavior=fb;
    }
    public void setQuackBehavior(QuackBehavior cb){
        quackBehavior=cb;
    }
    public void swim(){
        System.out.println("All ducks float,even decoys!!");
    }
}
View Code

MallardDuck类和ModelDuck类(MallardDuck.java与ModelDuck)

public class MallardDuck extends Duck{
    public MallardDuck(){
        quackBehavior=new Quack();
        flyBehavior=new FlyWithSwings();
    }
    public void display(){
        System.out.println("I'm a real Mallard Duck");
    }
}

public class ModelDuck extends Duck{
    public ModelDuck(){
        flyBehavior=new FlyNoWay();
        quackBehavior=new MuteQuack();
    }
    public void display(){
        System.out.println("I'm a model duck!!");
    }
}
View Code

FlyBehavior接口(FlyBehavior.java)与三个行为实现类(FlyWithWings.java、FlyNoWay.java和新增的FlyRocketPowered.java)

public interface FlyBehavior {
    public void fly();
}

public class FlyWithSwings implements FlyBehavior{
    public void fly(){
        System.out.println("I'm flying!!");
    }
}

public class FlyNoWay implements FlyBehavior{
    public void fly(){
        System.out.println("I can't fly!!");
    }
}

public class FlyRocketPowered implements FlyBehavior{
    public void fly(){
        System.out.println("I'm flying with a rocket!!");
    }
}
View Code

QuackBehavior接口(QuackBehavior.java)及其三个实现类(Quack.java、MuteQuack.java、Squeak.java)

 1 public interface QuackBehavior {
 2     public void quack();
 3 }
 4 
 5 public class Quack implements QuackBehavior{
 6     public void quack(){
 7         System.out.println("Quack!!");
 8     }
 9 }
10 
11 public class MuteQuack implements QuackBehavior{
12     public void quack(){
13         System.out.println("Silence!!");
14     }
15 }
16 
17 public class Squeak implements QuackBehavior{
18     public void quack(){
19         System.out.println("Squeak");
20     }
21 }
View Code

 测试类(MiniDuckSimulator.java)

public class MiniDuckSimulator {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Duck mallard=new MallardDuck();
        mallard.perfmormFly();
        mallard.performQuack();
        Duck model=new ModelDuck();
        model.perfmormFly();
        model.performQuack();
        model.setFlyBehavior(new FlyRocketPowered());
        model.perfmormFly();
    }
}
/*
 *
 * 运行结果:
 * Quack!!
 * I can't fly!!
 * Silence!!
 * I'm flying with a rocket!!
 */
View Code

 

这就是策略模式

策略模式(Strategy Pattern)定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。封闭可以互换的行为,并使用委托来决定要使用哪一个。

策略模式结构

Strategy:可由接口或抽象类来实现;定义所有支持的算法的公共接口;Context使用这个接口来调用某ConcreteStrategy定义的算法。

ConcreteStrategy:具体的策略实现,也就是具体的算法实现。

Context:用一个ConcreteStrategy对象来配置;维护一个对Strategy对象的引用;可定义一个接口来让Strategy访问它的数据。

策略模式示例代码

/**
 * 策略,定义算法的接口
 */
public interface Strategy {
    // 某个算法的接口,可以有传入参数,也可以有返回值
    public void algorithmInterface();
}

/**
 * 实现具体的算法
 */
public class ConcreteStrategyA implements Strategy {
    public void algorithmInterface() {
       //具体的算法实现   
    }
}
public class ConcreteStrategyB implements Strategy {
    public void algorithmInterface() {
       //具体的算法实现   
    }
}
public class ConcreteStrategyC implements Strategy {
    public void algorithmInterface() {
       //具体的算法实现   
    }
}

/**
 * 上下文对象,通常会持有一个具体的策略对象
 */
public class Context {
    //持有一个具体的策略对象
    private Strategy strategy;

     // 构造方法,传入一个具体的策略对象
     //@param aStrategy 具体的策略对象
    public Context(Strategy aStrategy) {
       this.strategy = aStrategy;
    }

     // 上下文对客户端提供的操作接口,可以有参数和返回值
    public void contextInterface() {
       //通常会转调具体的策略对象进行算法运算
       strategy.algorithmInterface();
    }
}

关于策略模式, 最后推荐一篇博文:http://www.uml.org.cn/sjms/201009092.asp

原文地址:https://www.cnblogs.com/aaron-shu/p/5096630.html