设计模式之策略模式


引入

书接上回,我们来聊聊啥是策略模式?
这是一个将算法封装起来的模式,然后提供一个set函数来让它们可以相互替换,这个模式让算法可独立于使用它的客户而变化。

适合用策略模式的场景

  • 一个类有很多种行为,使用这个模式可以避免在类中使用大量的条件语句(不同的用户调用,不要写成if判断是哪个用户,直接set设置就在同一个接口函数中表现出不一样的行为)
  • 程序不希望暴露复杂的、与算法相关的数据结构
  • 需要使用一个算法的不同变体

策略模式的定义

定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换。

策略模式的结构

在这里插入图片描述
在这里插入图片描述
上下文对象中引用这个策略接口,具体是策略继承这个策略接口。上下文只需要向这个策略接口发消息就可以了~

上下文对象

//上下文对象
public class GymnasticsGame {
    Computable strategy;//保存策略的引用
    //用于设置切换哪个具体策略
    public void setStrategy(Computable strategy){
        this.strategy = strategy;
    }
    //委托函数,客户端程序不直接调用策略,而通过上下文对象转发,实现策略对象的共享
    public double getPersonScore(double[] a){
        if (strategy!=null)
            return strategy.computeScore(a);//调用具体策略的方法
        else
            return 0 ;
    }
}

策略接口

//策略接口
public interface Computable {
    public abstract double computeScore(double[] a);
}

具体的三种策略

public class StrategyOne implements Computable{
    //实现计算数组a的元素的代数平均值
    @Override
    public double computeScore(double[] a) {
        double score =0 , sum =0;
        for (int i = 0; i < a.length; i++) {
            sum = sum +a[i];
        }
        score = sum/a.length;
        return score;
    }
}
public class StrategyTwo implements Computable{
    //实现计算数组a的元素的几何平均值
    @Override
    public double computeScore(double[] a) {
        double score =0 , multi =1;
        int n = a.length;
        for (int i = 0; i < a.length; i++) {
            multi = multi * a[i];
        }
        score = Math.pow(multi,1.0/n);
        return score;
    }
}

public class StrategyThree implements Computable{
    //去调一个最大值、一个最小值,实现计算数组a的剩余元素的代数平均值
    @Override
    public double computeScore(double[] a) {
        if(a.length<2)
            return 0 ;
        double score =0 ,sum = 0;
        Arrays.sort(a);
        for (int i = 0; i < a.length-1; i++) {
            sum = sum +a[i];
        }
        score = sum/(a.length-2);
        return score;
    }
}

应用程序

public class Application {
    public static void main(String[] args) {
        GymnasticsGame game = new GymnasticsGame(); //new一个上下文对象
        game.setStrategy(new StrategyOne());//上下文对象设置使用策略一
        Person albert = new Person();
        albert.setName("albert");
        double[] a = {9,12,2,4,64,2,45,6,12};
        albert.setScore(game.getPersonScore(a));//赋值语句,这个调用方式就是直接调用上下文对象的getPersonScore函数
        System.out.println(albert.getName()+" 使用算术平均值方案, 求出的值为: "+albert.getScore());

        game.setStrategy(new StrategyTwo());//重新set上下文的具体策略
        albert.setScore(game.getPersonScore(a));
        System.out.println(albert.getName()+" 使用几何平均值方案, 求出的值为: "+albert.getScore());
    }

    //建立一个内部类,完善业务场景逻辑
    private static class Person {
        String name;
        double score;
        public void setScore(double score) {
            this.score = score;
        }
        public void setName(String name) {
            this.name = name;
        }
        public double getScore() {
            return score;
        }
        public String getName() {
            return name;
        }
    }
}

在这里插入图片描述

从这里可以看出来,具体策略对象实例其实是应用程序对象创建的,上下文对象其实并不知道它要向哪个具体策略发消息,这为添加新的具体策略提供的方便;而应用程序本身也不用直接和具体策略对象发生交互,通过上下文对象的消息转发,可以让接口统一,达到一个接口不同表现的目的。


优点

  • 上下文对象和具体策略是松耦合关系,上下文只知道它要使用某一个实现strategy接口类的实例,但不需要知道具体是哪一个类
  • 策略模式满足开闭原则

策略模式相对于继承机制的优势

策略模式采用的是组合方法,即将一个类的某个方法内容的不同变体分别封装在不同的类中,而该类仅仅依赖这些类所实现的一个共同接口。上下文对象的修改并不会影响到具体策略,这正是组合比继承更有优势的地方

总结

策略模式其实就是将函数方法封装起来的一种模式,通过上下文对象来实现方法的转换,避免了我们要用大量的条件语句来判断使用哪些方法的尴尬,让上下文对象去调用具体策略,应用程序不需要知道算法的细节。
考虑到系统的扩展性和复用性,就要注意面向对象的一个基本原则之一:少用继承,多用组合。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AlbertOS

还会有大爷会打钱?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值