设计模式之策略模式

情景:

要设计很多鸭子,每个鸭子都有quack(呱呱叫)和swim功能。

可以设计一个Duck类,含有quack()和swim()方法就可以了。具体鸭子类继承Duck类。

新需求:要求添加fly功能。

如果直接给Duck添加fly()方法,会出现问题,因为有一部分鸭子是不会飞的。

选择创建Flyable接口,只有会飞的鸭子才继承接口,可以解决这一问题,但是造成代码无法复用。

设计原则:封装变化

找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。

因为鸭子的行为是变化的所以把鸭子的行为封装起来,创建一组行为类。

设计原则:针对接口编程,而不是针对实现编程。

针对接口编程的意思是: Animal animal = new Dog(); 而不是 Dog dog = new Dog(); 

Animal可以是超类或者接口,主要是通过多态,使得代码容易被扩展。

为每个行为写一个接口,行为的具体实现就是接口的一个实现类。这样具体行为就可以容易的被修改。

行为接口:

public interface FlyBehavior {
    public void fly();
}
-----------
public interface QuackBehavior {
    void quack();
}

实现行为的具体类:

public class FlyNoWay implements FlyBehavior {
    @Override
    public void fly() {
        System.out.println("I can't fly");
    }
}
……………………
public class FlyWithWings implements FlyBehavior {
    @Override
    public void fly() {
        System.out.println("I'm flying!");
    }
}
……………………
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 >>");
    }
}

Duck超类:

public abstract class Duck {
    
    FlyBehavior flyBehavior;
    QuackBehavior quackBehavior;
    
    public Duck() {
    }public void performFly() {
        flyBehavior.fly();    // 委托给行为类
    }
    
    public void performQuack() {
        quackBehavior.quack();
    }
    
    public void swim() {
        System.out.println("All ducks flost, even decoys!");
    }
    
    public void display() {
        System.out.println("I am a duck.");
    }
    
}

Duck一个具体实现类:

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

测试类:

public class MiniDuckSimulator {
    public static void main(String[] args) {
        Duck mallard = new MallardDuck();
        mallard.performQuack();
        mallard.performFly();
    }
}

输出:

Quack
I'm flying!

如果能在Duck类中通过setter动态设置行为,而不是只能在构造方法中绑定,就可以更灵活的改变鸭子的行为。

Duck类:

public abstract class Duck {
    
    FlyBehavior flyBehavior;
    QuackBehavior quackBehavior;
    
    public Duck() {
    }
    
    public void setFlyBehavior(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }

    public void setQuackBehavior(QuackBehavior quackBehavior) {
        this.quackBehavior = quackBehavior;
    }
    
    //......
}

新建一个模型鸭类型,默认不会飞

public class ModelDuck extends Duck {
    public ModelDuck() {
        flyBehavior = new FlyNoWay();
        quackBehavior = new Quack();
    }
    public void display() {
        System.out.println("I am a model duck.");
    }
}

然后建立一个火箭动力类(???)

public class FlyRocketPowered implements FlyBehavior {
    @Override
    public void fly() {
        System.out.println("I am flying with a rocket.");
    }
}

通过动态改变行为,模型鸭就可以飞啦~~

public class MiniDuckSimulator {
    public static void main(String[] args) {
        Duck model = new ModelDuck();
        model.performFly();
        model.setFlyBehavior(new FlyRocketPowered());
        model.performFly();
    }
}

输出:

I can't fly
I am flying with a rocket.

 

把鸭子的行为封装起来,这样可以自由的改变鸭子的行为,也方便对行为的扩展。

把行为改变为算法,就是策略模式。

设计原则:多用组合,少用继承。

 

策略模式:定义了算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于算法的客户。

类图:

(讲道理我觉得书上这个例子举得一点都不好。。。。)

 

 一个简单的例子:

public interface Strategy {
    public int doOperator(int num1, int num2);
}
……………………
public class AddStrategy implements Strategy {
    @Override
    public int doOperator(int num1, int num2) {
        return num1 + num2;
    }
}
……………………
public class SubStrategy implements Strategy {
    @Override
    public int doOperator(int num1, int num2) {
        return num1 - num2;
    }
}
……………………
public class MulStrategy implements Strategy {
    @Override
    public int doOperator(int num1, int num2) {
        return num1 * num2;
    }
}
……………………
public class Context {
    
    Strategy strategy;
    
    public Context(Strategy strategy) {
        this.strategy = strategy;
    }
    
    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }
    
    public int doOperator(int num1, int num2) {
        return strategy.doOperator(num1, num2);
    }
    
}

测试类:

public class Main {
    public static void main(String[] args) {
        Context context = new Context(new AddStrategy());
        System.out.println(context.doOperator(2, 3));
        context.setStrategy(new SubStrategy());
        System.out.println(context.doOperator(2, 3));
        context.setStrategy(new MulStrategy());
        System.out.println(context.doOperator(2, 3));
    }
}
/*
Output:
5
-1
6
*/

 

posted @ 2017-03-06 18:35  我不吃饼干呀  阅读(168)  评论(1编辑  收藏  举报