美文网首页Android精选
设计模式(一)之策略模式

设计模式(一)之策略模式

作者: 探索的影子 | 来源:发表于2019-01-19 18:00 被阅读28次

    问题场景
    现在我们设计好了以下类


    image.png

    超类鸭子,不同的鸭子外观是不一样的,所以展示的方法是抽象的方法。不同种类的鸭子都继承duck,并重写展示方法。

    需求-----鸭子是可以飞的

    有一天项目经理说:“鸭子是可以飞的”。那么这个时候,你也许会直接想到要不直接在超类里面写一个fly的方法。这样所有继承的鸭子都可以实现fly的方法。
    貌似这样好像没有什么问题,这样所有的子类都可以实现飞翔。


    image.png

    bug---塑料鸭子在天上飞

    随着项目的进行,项目里面需要创建一个塑料鸭子的类,根据我们的oo设计原则,我们应该继承duck类。这样就会有个问题
    塑料鸭子也具备了天上飞的方法,想想是不是有点毛骨悚然。所有继承的问题就出现了:虽然很多时候,继承都能够完成代码的复用,但是破坏了封装,不是所有的鸭子都是可以飞翔的。继承是不能够采用了。

    改进---实现接口

    这时候,你肯定会想到既然继承不行,那我就实现接口。写一个flyable接口,每一个可以飞的鸭子类我实现它这样的话,就可以解决塑料鸭子在天上飞的问题了。

    问题---代码复用度不够

    虽然解决了塑料鸭子在天上飞的问题,但是有一个隐藏的问题:复用度不够,代码反复写。这里只有两种鸭子,但是如果有二十多种鸭子呢?难道我们要写二十多次?聪明的程序员都是会偷懒的。那么有没有种简单的方式,解决这种问题呢?

    解决---成员变量实现

    划重点
    设计原则

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

    在这里飞行是变化的部分,不是所有的鸭子都是可以飞翔的。所以我们需要将这个行为提取出来,组建成一个新的类来代表飞行的行为。


    image.png

    我不清楚这样的uml表达是否是准确的所以我也贴上代码:

    抽象父类duck
    package com.yyh.StrategyPattern;
    
    /**
     * 抽象父类
     */
    public abstract class Duck {
        private FlyBehavior flyBehavior;
        public void swimming(){
            System.out.println("duck.swimming");
        }
    
        public void quack(){
            System.out.println("duck.quack");
        }
    
        public abstract void display();
    
        public FlyBehavior getFlyBehavior() {
            return flyBehavior;
        }
    
        public void setFlyBehavior(FlyBehavior flyBehavior) {
            this.flyBehavior = flyBehavior;
        }
    }
    
    
    MallardDuck
    package com.yyh.StrategyPattern;
    
    public class MallardDuck extends Duck {
        private FlyBehavior flyBehavior;
        @Override
        public void display(){
            System.out.println("MallardDuck.绿头");
        }
    }
    
    
    RedheadDuck
    package com.yyh.StrategyPattern;
    
    public class RedheadDuck extends Duck {
        private FlyBehavior flyBehavior;
        @Override
        public void display(){
            System.out.println("RedheadDuck.红头");
        }
    }
    
    
    
    RubberDuck
    package com.yyh.StrategyPattern;
    
    public class RubberDuck extends Duck {
    
        @Override
        public void display(){
            System.out.println("RedheadDuck.塑料的");
        }
    
    
    }
    
    
    FlyBehavior
    package com.yyh.StrategyPattern;
    
    public interface FlyBehavior {
    
        void fly();
    }
    
    
    
    FlyWithWings
    package com.yyh.StrategyPattern;
    
    public class FlyWithWings implements FlyBehavior {
        @Override
        public void fly() {
            System.out.println("通过翅膀飞行");
        }
    }
    
    
    
    FlyNoWay
    package com.yyh.StrategyPattern;
    
    public class FlyNoWay implements FlyBehavior {
        @Override
        public void fly() {
            System.out.println("原地蹦跶了一下");
        }
    }
    
    
    测试类
    package com.yyh.StrategyPattern;
    
    public class TestMain {
        public static void main(String[] args) {
            Duck mallardDuck = new MallardDuck();
            mallardDuck.setFlyBehavior(new FlyWithWings());
            Duck redheadDuck = new RedheadDuck();
            redheadDuck.setFlyBehavior(new FlyWithWings());
            Duck rubberDuck = new RubberDuck();
            rubberDuck.setFlyBehavior(new FlyNoWay());
            System.out.println("mallardDuck:");
            mallardDuck.getFlyBehavior().fly();
            System.out.println("redheadDuck:");
            redheadDuck.getFlyBehavior().fly();
            System.out.println("rubberDuck:");
            rubberDuck.getFlyBehavior().fly();
        }
    }
    
    

    测试结果

    image.png

    分析

    这样的话,我们没有删除曾经的业务逻辑,只是添加了一个成员变量就解决了不同鸭子的飞行问题。并且通过set方式的话,可以在程序运行的时候,动态改变行为。

    动态改变行为

    如果我们在运行的过程中,给红头鸭子一个火箭,让它坐火箭飞行呢?其实我们就只需要写一个新的飞的实现类就可以了。在程序指定的位置set一下,就可以改变鸭子的行为了,

    FlyWithRocket
    package com.yyh.StrategyPattern;
    
    public class FlyWithRocket implements FlyBehavior {
        @Override
        public void fly() {
            System.out.println("坐火箭,惊了~~");
        }
    }
    
    
    新的测试类
    package com.yyh.StrategyPattern;
    
    public class TestMain {
        public static void main(String[] args) {
            Duck mallardDuck = new MallardDuck();
            mallardDuck.setFlyBehavior(new FlyWithWings());
            Duck redheadDuck = new RedheadDuck();
            redheadDuck.setFlyBehavior(new FlyWithWings());
            Duck rubberDuck = new RubberDuck();
            rubberDuck.setFlyBehavior(new FlyNoWay());
            System.out.println("mallardDuck:");
            mallardDuck.getFlyBehavior().fly();
            System.out.println("redheadDuck:");
            redheadDuck.getFlyBehavior().fly();
            System.out.println("rubberDuck:");
            rubberDuck.getFlyBehavior().fly();
            System.out.println("==动态修改状态====:");
            //坐火箭上天
            redheadDuck.setFlyBehavior(new FlyWithRocket());
            System.out.println("redheadDuck:");
            redheadDuck.getFlyBehavior().fly();
        }
    }
    
    

    测试结果


    image.png

    笔记

    设计原则

    少用继承,多用组合
    

    策略模式定义

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

    喜欢和评论是我更新和学习的最大动力,谢谢!

    相关文章

      网友评论

        本文标题:设计模式(一)之策略模式

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