• 【一起学系列】之策略模式:好多鸭子啊


    普遍定义

    定义个一个算法族, 各个算法的实现可以相互替换, 算法的实现和具体的算法使用场景隔离

    策略模式的进化

    产品】:我需要一堆鸭子,红色的,绿色的,黑色的,还要会飞!还要会叫!

    开发】:明白,秒秒钟搞定,N种鸭子只要继承了我的Duck类然后重写,就搞定一切!

    public abstract class Duck {
        /**
         * 颜色属性
         */
        String color;
    
        /**
         * 飞行方法
         */
        fly();
    
        /**
         * 呱呱叫的方法
         */
        quack();
    }
    

    Some times later…


    BOSS】:磕大头!你怎么回事!!!你能不能告诉我为什么橡皮鸭子会在天上飞!!!???

    开发】:(不敢说话,只有内心独白: 原来无脑继承会出大问题啊… 我是谁… 我在哪… 我该怎么办…)

    在这里插入图片描述

    磕大头的十万个问题

    Q1. 以后还有很多奇奇怪怪的情况,谁知道老板哪天要不要让橡皮鸭也飞起来,我该怎么办?

    Q2. 只用封装,继承好像不行,好像还有一个多态?

    Q3. 我该怎么使用多态呢?

    Q4. 我是不是可以把飞这个行为定义成接口,然后把这个接口… 放到鸭子基类里面去!!!

    在这里插入图片描述

    核心代码

    public abstract class Duck {
        /**
         * 飞行行为是动态的,可能会变的,因此抽成多个接口的组合,而不是让Duck类继承
         */
        FlyBehavior flyBehavior;
    
        /**
         * 每个鸭子的叫声不同,抽象成接口
         */
        QuackBehavior quackBehavior;
    }
    

    这下子,好像真的就解决了呢,想怎么飞就怎么飞,想怎么叫就怎么叫

    遵循的设计原则

    • 封装变化
    • 多用组合,少用继承
    • 针对接口编程,而不是针对实现编程

    我之前的理解误区

    大家在初学Java的时候,肯定都绕不开设计模式这一Part,那个时候我对策略模式的认知是这样的,核心代码如下:

    // 不需要看全貌,就看这一段核心代码
    public strategyChoose(String mainName){
        switch (name){
            case "A":
                story = new StoryB(name);
                break;
            case "B":
                story = new StoryA(name);
                break;
            default:
                story = new StoryB(name);
                break;
        }
    }
    

    以下是错误理解:

    我之前认为,策略模式,顾名思义就是定义不同的策略(即算法),然后动态的调用就好了,比如我定义A,B两种策略,然后通过Switch分支语句选择策略就可以

    这样理解的错误点在于:错误的理解了策略模式的重点,而误把工厂模式的策略选择当作策略模式

    现在的理解:

    • 设计模式肯定有其变种,我们不需要太拘泥于条条框框而限制了自我
    • 任何定义都有其普遍的理解,我们在突破自我的同时,不能完全走偏
    • 所以真正的策略模式核心即:封装行为,依赖接口,组合代替继承

    为什么策略模式常和工厂模式或枚举混用?

    首先我们知道了策略模式最初的起源和关键点:行为或者说算法的抽象及接口的组合

    那么问题来了,在我们拥有多种策略的时候,策略的数量和类型会大大增加,那么调用N种策略肯定需要一个简单的逻辑进行更好的调用,那么策略枚举,或者简单工程则会成为我们最先考虑的方式之一,也正因为如此,才会有上文中我出现的理解误区

    生活中的策略模式

    • LOL里我喜欢玩奶妈,因为奶妈可以加血,那么在英雄技能设计上,加血是一种行为,具体的细节每个英雄都不一样,这就是策略模式的一种体现

    • 比如支付场景中我们会抽取支付信息中的订单,状态,付款人,金钱等等信息,但是支付的细节可以是支付宝也可以是微信

    真假策略模式

    写这篇文章的时候,在网上也查询了很多资料,发现大家的策略模式总有一些细枝末节不一样的地方,接下来会展示一部分代码,大家可以主观来判断一下它是否属于策略模式,是否可以用其他设计模式代替

    /**
     * 网络玄幻小说的故事梗概接口
     * 固定的一些套路
     * 策略模式:网络小说的固定套路
     */
    public interface Synopsis {
        /**
         * 穷困潦倒的开始
         */
        void badStart();
    
        /**
         * 突然有天遇到神人/捡到神器,实力大涨
         */
        void adventure();
    
        /**
         * 在一场战斗中以弱胜强
         */
        void winABattle();
    
        /**
         * 从此飞速成长
         */
        void growFast();
    
        /**
         * 组团刷怪,经历九死一生(主角怎么也死不了)
         */
        void manyFights();
    
        /**
         * 最终功成名就,妻妾成群
         */
        void succeed();
    
        /**
         * 组合起来就是小说内容
         */
        void getContent();
    }
    
    
    /**
     * 故事 A ,恶魔法则
     */
    public class StoryA implements Synopsis {
        // 实现省略
    }
    
    /**
     * 故事 B ,诛仙
     */
    public class StoryB implements Synopsis {
        // 实现省略
    }
    

    策略选择类:

    /**
     * 策略选择类
     */
    public class WriteNovel {
        private Synopsis mSynopsis;     //故事梗概
        private String mMainActorName;  //主角名称
    
        /**
         * 梗概、内容都差不多确定后,换个名称就是另一部小说
         * @param mainName
         */
        public WriteNovel(String mainName){
            switch (mainName){
                case "张小凡":
                    mSynopsis = new StoryB(mainName);
                    break;
                case "杜维":
                    mSynopsis = new StoryA(mainName);
                    break;
                default:
                    mSynopsis = new StoryB(mainName);
                    break;
            }
        }
    
        /**
         * 获取小说内容
         */
        public void getNovelDetail(){
            mSynopsis.getContent();
        }
    }
    

    最后

    附上策略模式的UML图

    在这里插入图片描述

    然后再说一个暖心小故事~

    在2020年5月6日的时候,我发现了掘金的一个BUG,整个界面都加载不出来(已经修复啦~)

    第二天我找到了掘金首席产品体验官优弧小姐姐,跟她积极反馈了BUG,同时小小的推荐了一下子自己的文章,然后发了许久的一篇文章就这样再一次上了热门第一名,实证如下(开心到爆炸):

    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    HDU 4644 BWT (KMP)
    常数的值类型问题
    HDU 1395 2^x mod n = 1 (欧拉函数)
    HDU 5384 Danganronpa(AC自动机)
    9.自己实现linux中的tree
    8.底层文件库
    7.标准文件库
    7.gcc的使用
    5.文件I/O
    4.vim操作
  • 原文地址:https://www.cnblogs.com/kkzhilu/p/12859483.html
Copyright © 2020-2023  润新知