美文网首页踢出来的设计模式Java学习笔记
Strategy模式:橡皮鸭子不会飞

Strategy模式:橡皮鸭子不会飞

作者: 和坚 | 来源:发表于2017-01-24 17:18 被阅读33次

需求故事

    1. 作为黄鸭子,我希望可以display “Yellow Duck”,可以fly "Yellow Duck Fly"
    1. 作为灰鸭子,我希望可以display “Gray Duck”,可以fly “Gray Duck Fly”
    1. 作为橡皮鸭子, 我希望可以display “Rubber Duck”,可以fly ”Rubber Duck can not Fly“

Story1

Story1 Test Case

public class DuckTest {
    @org.junit.Test
    public void testDuckFly(){
        //Story 1
        YellowDuck yellowDuck = new YellowDuck();
        assertEquals("Yellow Duck", yellowDuck.display());
        assertEquals("Yellow Duck Fly", yellowDuck.fly());
    }
}

Story1 Implementation

Story2

Story2 Test case

public class DuckTest {
    @org.junit.Test
    public void testDuckFly(){
        //Story 1
        Duck yellowDuck = new YellowDuck();
        assertEquals("Yellow Duck", yellowDuck.display());
        assertEquals("Yellow Duck Fly", yellowDuck.fly());
        //Story 2
        Duck grayDuck = new GrayDuck();
        assertEquals("Gray Duck", grayDuck.display());
        assertEquals("Gray Duck Fly", grayDuck.fly());
    }
}

增加Story2的Test case时,发现YellowDuck和GrayDuck由于有相同的行为,所以可以抽象成Duck,这样test case也都是真对duck的。

Story2 Implementation

在实现这两个Story的TestCase时,发现三个行为可以在Duck中实现

public class Duck {
    protected String duckType = "";
    protected FlyBehavior flyBehavior;
    private static String duckStr = "Duck";
    public String display() {
        return new StringBuilder(duckType).append(" ").append(duckStr).toString();
    }
    public String fly() {
        ...
    }   
}

public class YellowDuck extends Duck {
    public YellowDuck(){
        super.duckType = "Yellow";
    }
}

public class GrayDuck extends Duck {
    public GrayDuck(){
        super.duckType = "Gray";
    }
}

第二步 增加Rubber Duck到Test Case中

增加的TestCase在没有修改Duck的情况下是肯定失败的

public class DuckTest {

    @org.junit.Test
    public void testDuckFly(){

        //Story 1
        Duck yellowDuck = new YellowDuck();
        assertEquals("Yellow Duck", yellowDuck.display());
        assertEquals("Yellow Duck Fly", yellowDuck.fly());

        //Story 2
        Duck grayDuck = new GrayDuck();
        assertEquals("Gray Duck", grayDuck.display());
        assertEquals("Gray Duck Fly", grayDuck.fly());

        //Story 3
        Duck rubberDuck = new RubberDuck();
        assertEquals("Rubber Duck", rubberDuck.display());
        assertEquals("Rubber Duck can not Fly", rubberDuck.fly());
        
    }
}

这时候其实让上述testcase实现的最简单的方法是在Duck的Fly方法之中增加if语句,if RubberDuck就走另外一套Fly方法。但是这种简单方法是很脆弱的,因为如果有一个RocketDuck可以用Rocket飞,那么就有要修改Duck的代码了。
所以我们发现fly这个行为是一个可能变化的行为,那么我们需要对变换抽象,把行为抽象成接口FlyBehavior,然后能飞和不能飞是这个接口的两个实现。Duck本身只负责调用接口FlyBehavior就可以了,具体的Duck子类才需要知道究竟FlyBehavior的实现是什么。

public interface FlyBehavior {
    public String fly(String duckType, String duckStr);
}

public class FlyWithWings implements FlyBehavior {
    @Override
    public String fly(String duckType, String duckStr) {
        return new StringBuilder(duckType).append(" ").append(duckStr).append(" Fly").toString();
    }
}

public class FlyNoWay implements FlyBehavior {
    @Override
    public String fly(String duckType, String duckStr) {
        return new StringBuilder(duckType).append(" ").append(duckStr).append(" can not Fly").toString();
    }
}


public class Duck {

    protected String duckType = "";
    protected FlyBehavior flyBehavior;
    private static String duckStr = "Duck";

    public String display() {
        return new StringBuilder(duckType).append(" ").append(duckStr).toString();
    }

    public String fly() {
        return flyBehavior.fly(duckType,duckStr);
    }
}

public class YellowDuck extends Duck {
    public YellowDuck(){
        super.duckType = "Yellow";
        super.flyBehavior = new FlyWithWings();
    }
}

public class RubberDuck extends Duck {
    public RubberDuck(){
        super.duckType = "Rubber";
        super.flyBehavior = new FlyNoWay();
    }
}

和坚思辨

Strategy模式的本质其实就是变化行为的封装,把一个行为从继承变成了组合关系。这样做的好处就是在行为发生变化的时候不需要去改动行为对应的父类
当发现下面的情景时,就应该考虑是不是可以用Strategy模式来解决问题了。

  • 给一个父类增加了一个新子类,结果发现父类需要修改方法来判断子类的类型,这代表着父类的行为随着子类而变化。

相关文章

  • Strategy模式:橡皮鸭子不会飞

    需求故事 作为黄鸭子,我希望可以display “Yellow Duck”,可以fly "Yellow Duck ...

  • 王者荣耀之「策略者模式」

    目录 什么策略模式(Strategy)1.1 Strategy模式的定义1.2 为什么用Strategy模式,他的...

  • (GeekBand)C++设计模式 第一周学习笔记

    Strategy模式 今天重点来介绍下Strategy模式。 作为三大经典“组件协作”模式之一的Strategy模...

  • 设计模式用例(三)

    Strategy 模式 Bridge 模式 Iterator 模式

  • 鸭子为什么不会飞?

    春暖花开,鸭妈妈带着小鸭们在山坡上悠闲的享受阳光浴。 这时一身洁白羽毛的大天鹅从南方过冬归来,看到鸭妈妈就飞过去问...

  • STRATEGY 模式

    STRATEGY 模式 一.定义 定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。 二.类图 三....

  • strategy模式

    按照自己的理解就是: 一个策略完成的方法有多种,具体的实现类里面包含一个策略虚基类的指针,根据子类实例化的类调用具...

  • Strategy 模式

    证券交易费用 佣金 brokerage 证监会交易征费 SFC Transaction Levy 财务汇报局交易征...

  • 设计模式之策略模式

    策略模式 Strategy Intro 策略模式(Strategy):它定义了算法家族,分别封装起来,让它们之间可...

  • 「碎语杂记」煮熟的鸡蛋孵出了鸡

    不止一次听人说过,煮熟的鸭子飞了。煮熟的鸭子会飞吗?不会,肯定不会。不仅煮熟的飞不了,在我朴素的认知中,八分熟,半...

网友评论

    本文标题:Strategy模式:橡皮鸭子不会飞

    本文链接:https://www.haomeiwen.com/subject/vhnzbttx.html