zoukankan      html  css  js  c++  java
  • 策略模式

    概念:

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

      很多同学可能不太理解这个定义,我举个简单的例子,比如客户要实现一个功能,分为A,B,C,D4个步骤完成,其中A和C步骤是很容易发生改变的,所以我们将A和C步骤分别封装起来,

      具体实现方式是将A和C定义为接口,各自分别有1,2,3种实现方式。此时A和C对应的就是算法族,各自的实现叫做算法,各个算法之间可以相互替换,来达到不同的实现目的。客户

      需要实现的功能可以由A和C算法族组合实现各式各样不同的功能,而我们实现功能的主干永远不会改变。

    设计原则:

      上面的小例子也用到了几个设计原则:

      1,将程序中可能需要改变的部分独立出来,不要和不需要变化的代码放在一起。

      2,针对接口编程,而不是针对实现编程。

      3,少用继承,多用组合。

      第1点相信大家都能理解,但是在实际工作中,要完美的运用实际上并没有那么简单。

      第2点,先说说针对接口编程的好处,就比如例子中,主干功能代码不需要任何改变,我们就能实现各种不同功能的实现,精髓就在各个具体的算法实现了一个接口,我们只需要传入不同的具体的实现

      就能轻松实现不同的功能。如果你不理解为什么能这样做,那你可能还不理解java的多态,父类引用指向子类对象。我们也可以通过这个例子来反向理解多态,你会发现原来多态就是这样,so easy!

      第3点,少用继承,多用组合。继承太过于笨重,如果我继承某个接口或者类,我就必须实现这个接口或者类的所有方法,这显然是不合理的,组合就不一样了,我可以任意组合实现各种各样的功能。

      比如A的一种具体实现和C的一种具体实现就是一类组合,这里我们可以实现3x3=9种组合,也就意味着有9种实现该功能的方式,如果需要增加,我们只需要增加一种实现类,而不需要修改主干的任意

      代码就能轻易实现。

    代码实现:

      这里举一个简单的小例子,比如某明显开一场演唱会,后台调音师需要根据明星演唱的歌曲准备背景音乐。这里就可以运用策略模式去实现。

      1,先定义一个背景音乐的接口,创建一个播放的方法。

    package strategy;
    
    /**
     * @ClassName BackgroundMusic
     * @Description 背景音乐接口
     * @Author liuyi
     * @Date 2020/6/14 11:08
     * @Version 1.0
     */
    public interface BackgroundMusic {
        /**
         * @Author liuyi
         * @Description 定义播放的方法
         * @Date 11:10 2020/6/14
         * @Param []
         * @return void
         **/
        public void play();
    }
    

      

    2,分别有三种背景音乐去实现该接口

      背景音乐1

    package strategy;
    
    /**
     * @ClassName BackgroundMusic1
     * @Description TODO
     * @Author liuyi
     * @Date 2020/6/14 11:12
     * @Version 1.0
     */
    public class BackgroundMusic1 implements BackgroundMusic {
        @Override
        public void play() {
            System.out.println("开始播放背景音乐1");
        }
    }
    

      背景音乐2

    package strategy;
    
    /**
     * @ClassName BackgroundMusic2
     * @Description TODO
     * @Author liuyi
     * @Date 2020/6/14 11:13
     * @Version 1.0
     */
    public class BackgroundMusic2 implements BackgroundMusic{
        @Override
        public void play() {
            System.out.println("开始播放背景音乐2");
        }
    }
    

      背景音乐3

    package strategy;
    
    /**
     * @ClassName BackgroundMusic3
     * @Description TODO
     * @Author liuyi
     * @Date 2020/6/14 11:13
     * @Version 1.0
     */
    public class BackgroundMusic3 implements BackgroundMusic {
        @Override
        public void play() {
            System.out.println("开始播放背景音乐3");
        }
    }
    

      3,创建背景音乐编号枚举类

    package strategy;
    
    /**
     * @ClassName MusicNumEnum
     * @Description 背景音乐编号枚举类
     * @Author liuyi
     * @Date 2020/6/14 11:20
     * @Version 1.0
     */
    public enum MusicNumEnum {
        music1(1,"strategy.BackgroundMusic1"),
        music2(2,"strategy.BackgroundMusic2"),
        music3(3,"strategy.BackgroundMusic3");
    
        MusicNumEnum(int num, String className){
            this.num = num;
            this.className = className;
        }
        //编号
        private int num;
        //类名称
        private String className;
    
        public int getNum() {
            return num;
        }
    
        public void setNum(int num) {
            this.num = num;
        }
    
        public String getClassName() {
            return className;
        }
    
        public void setClassName(String className) {
            this.className = className;
        }
        //根据num获取className
        public static String getClassNameByNum(int num){
            MusicNumEnum[] values = MusicNumEnum.values();
            for (MusicNumEnum value : values) {
                if(value.getNum()==num){
                    return value.getClassName();
                }
            }
    
            return null;
        }
    
    }
    

      4,测试

    package strategy;
    
    /**
     * @ClassName StrategyTest
     * @Description 策略模式测试类
     * @Author liuyi
     * @Date 2020/6/14 11:16
     * @Version 1.0
     */
    public class StrategyTest {
        public static void main(String[] args) throws Exception {
            palyByNum(1);
            palyByNum(3);
            palyByNum(2);
        }
        /**
         * @Author liuyi
         * @Description 根据播放编号播放对应的背景音乐
         * @Date 11:41 2020/6/14
         * @Param [num]
         * @return void
         **/
        public static void palyByNum(int num) throws Exception{
            //根据背景音乐编号播放对应的背景音乐
            BackgroundMusic backgroundMusic = (BackgroundMusic)(Class.forName(MusicNumEnum.getClassNameByNum(num)).newInstance());
            backgroundMusic.play();
        }
    }
    

      从代码可以看出我们需要播放某个因为,只需要传入对应的编号即可,不需要对主干代码进行修改。如果下场演唱会需要新增背景音乐,则添加一个背景音乐类,然后在枚举类配置对应的编号和类的关系即可。

    从策略模式的概念来看,每一种背景音乐其实就是一种具体的算法,背景音乐1,背景音乐2,背景音乐3它们之间可以互相替换,来达到不同的目的,而使用的客户是不需要知道这些的存在的, 用户只需要传入算法

    对应的编号或者类型即可。

      

  • 相关阅读:
    sublime3使用
    内存缓存 ehcache
    一些服务端写代码的规范,很重要
    对于算法的一点思考
    使用单元测试引发的一些思考
    在多线程中使用spring的bean
    一个线上缓存异常
    java 中的同步机制
    微服务中的集成测试
    服务升级中的zookeeper
  • 原文地址:https://www.cnblogs.com/liu-yi/p/13082257.html
Copyright © 2011-2022 走看看