美文网首页
策略模式(封装可以互换的行为,并使用委托来决定要使用哪一个)

策略模式(封装可以互换的行为,并使用委托来决定要使用哪一个)

作者: 钉某人 | 来源:发表于2017-11-06 20:08 被阅读0次
    源码地址 https://github.com/DingMouRen/DesignPattern
    策略模式.png
    • Context------用来操作策略的对象
    • Stragety------策略的抽象
    • ConcreteStragetyA、ConcreteStragetyB ------具体策略的实现
    定义

    策略模式定义一系列的算法,把它们一个个封装起来 , 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。

    使用场景
    • 许多相关的类仅仅是具体实现不同。
    • 处理同一个问题,但是有不同的算法实现。
    • 一个类定义了多种行为,并且这些行为在这个类的操作中会以if-else或者switch-case的形式出现时。
    协作
    • Strategy与Context相互作用来实现选定的算法。当算法被调用时,Context可以将该算法所需要的所有数据都传递给该Strategy。或者,Context可以将自身作为一个参数传递给Strategy操作。这就让Strategy在需要时可以回调Context
    • Context将它的客户的请求转发给它的Strategy。客户通常创建并传递一个ConcreteStrategy对象给该Context,这样客户端仅需要与Context交互。通常有一系列的ConcreteStrategy类可供客户端从中选择。
    举个栗子

    一个学生要获取到数字6,他有多种算法。

    一般做法:假设在类Student中实现获取到数字6的算法getNumberSix(),如果老师要求使用相加的方式来实现,那么我们就用相加的方式来实现;没多久老师又让我们用相乘的方式来实现,好吧,我们再写相乘方式的算法;又没多久老师让我再以相减的方式来实现,我们又得回到Student类添加if-else,又对代码进行修改,违背了OO的开闭原则,设计的类应该是对扩展开放,对修改关闭。

     //获取到数字6
        public void getNumberSix(String str){
            if (str.equals("相加")){
                addMethod();//相加的方式获取到数字6
            }else if (str.equals("相乘")){
                multiMethod();//相乘的方式获取到数字6
            }else if (str.equals("相减")){
                subtractMethod();//通过相减的方式获取到数字6
            }
        }
    

    思考:我们想让Student类一旦编写结束,尽量不要再修改它,获取到数字6的算法有多种,怎么办呢?考虑到java的封装与多态,我们可以将算法封装成一个类,再向上抽象,抽象成一个接口,这个接口有一个方法(获取数字6的算法),每一个实现类都要实现这个方法。我们通过聚合的方式,将接口通过类Student的构造函数作为一个成员变量置于Student类中,在Student类的getNumberSix()方法中调用接口的方法。接口实现类负责具体算法的实现,比如相加获取6,相乘获取6,Studnet类要获取数字6的话,就在创建Student时传入接口实现类,java多态自动向上转型,传入的类型都是接口类型的,然后在调用getNumberSix()时,java的向下转型和运行时类型判断就起到了关键作用,这时调用的方法就是当时传入的接口实现类的方法。如果老师还想要其他的算法要求的话,只要实现接口的方法,传入新的算法就行了,这样就非常容易扩展了,也不用修改Student类。为了可以动态的更换算法,我们添加一个set方法,就可以实现动态更换算法了。

    //学生
    public class Student {
        private Stragety stragety;//策略的抽象,也可以称作泛化
    
        public Student(Stragety stragety) {
            this.stragety = stragety;
        }
    
        /**
         * 获取数字6
         */
        public void getNumberSix(){
            int result = stragety.calculate();
            System.out.println(result == 6 ? "获取的数字正确":"获取的数字不正确,获取到的数字是"+result);
        }
    
        /**
         * 可以动态的更换策略
         * @param stragety
         */
        public void setStragety(Stragety stragety) {
            this.stragety = stragety;
        }
    
    }
    
    
    //策略的抽象
    public interface Stragety {
        int calculate();//获取到数字6的方法抽象
    }
    //具体策略的实现:相加
    public class StragetyAdd implements Stragety {
        /**
         * 具体算法的实现:通过相加的方式获取到数字6
         * @return
         */
        @Override
        public int calculate() {
            int result = 0;
            for (int i = 0; i < 6; i++) {
                result += 1;
            }
            return result;
        }
    }
    //具体策略的实现:相乘的
    public class StargetyMultiply implements Stragety{
        /**
         * 具体算法的实现:通过相乘的方式获取到数字6
         * @return
         */
        @Override
        public int calculate() {
            int result = 2 * 3;
            return result;
        }
    }
    

    使用

    public static void main(String[] args) {
            //创建对象
            Student student = new Student(new StragetyAdd());
            //获取到数字6
            student.getNumberSix();
            //动态更换策略
            student.setStragety(new StargetyMultiply());
            student.getNumberSix();
        }
    
    总结

    优点

    • 结构清晰,使用简单
    • 耦合度相对较低
    • 扩展方便
    • 操作封装后,数据更加安全
      缺点
    • 随着策略的增加,子类会变得繁多

    相关文章

      网友评论

          本文标题:策略模式(封装可以互换的行为,并使用委托来决定要使用哪一个)

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