您的位置:  首页 > 技术杂谈 > 正文

如何用策略模式,优化你代码里的的if-else?

2021-07-24 22:06 CSDN 敖 丙 次阅读 条评论
本次就来具体聊聊策略模式它是如何做到行为解耦
大纲
定义

什么是策略模式?它的原理实现是怎么样的?

    定义一系列算法,封装每个算法,并使他们可以互换,不同的策略可以让算法独立于使用它们的客户而变化。 以上定义来自设计模式之美

感觉有点抽象?那就来看一张结构图吧

       

Strategy(抽象策略):抽象策略类,并且定义策略执行入口

        ConcreteStrategy(具体策略):实现抽象策略,实现algorithm方法
        Context(环境):运行特定的策略类。

这么看结构其实还是不复杂的,而且跟状态模式类似。

那么这个代码怎么实现?

举个例子,汽车大家肯定都不陌生,愿大家早日完成汽车梦,汽车的不同档(concreteStrategy)就好比不同的策略,驾驶者选择几档则汽车按几档的速度前进,整个选择权在驾驶者(context)手中。

public interface GearStrategy {

    // 定义策略执行方法
    void algorithm(String param);
}



首先还是先定义抽象策略

    这里是用接口的形式,还有一种方式可以用抽象方法abstract来写也是一样的。具体就看大家自己选择了。

    public abstract class GearStrategyAbstract {
     // 定义策略执行方法
     abstract void algorithm(String param);
    }




public class GearStrategyOne implements GearStrategy {

    @Override
    public void algorithm(String param) {
        System.out.println("当前档位" + param);
    }
}




其次定义具体档位策略,实现algorithm方法。

public class Context {
        // 缓存所有的策略,当前是无状态的,可以共享策略类对象
    private static final Map<String, GearStrategy> strategies = new HashMap<>();

    // 第一种写法
    static {
        strategies.put("one", new GearStrategyOne());
    }

    public static GearStrategy getStrategy(String type) {
        if (type == null || type.isEmpty()) {
            throw new IllegalArgumentException("type should not be empty.");
        }
        return strategies.get(type);
    }

    // 第二种写法
    public static GearStrategy getStrategySecond(String type) {
        if (type == null || type.isEmpty()) {
            throw new IllegalArgumentException("type should not be empty.");
        }
        if (type.equals("one")) {
            return new GearStrategyOne();
        }
        return null;
    }


    public static void main(String[] args) {
        // 测试结果
        GearStrategy strategyOne = Context.getStrategy("one");
        strategyOne.algorithm("1档");
         // 结果:当前档位1档
        GearStrategy strategyTwo = Context.getStrategySecond("one");
        strategyTwo.algorithm("1档");
        // 结果:当前档位1档
    }

}




最后就是实现运行时环境(Context),你可以定义成StrategyFactory,但都是一个意思。

在main方法里面的测试demo,可以看到通过不同的type类型,可以实现不同的策略,这就是策略模式主要思想。

在Context里面定义了两种写法:

        第一种是维护了一个strategies的Map容器。用这种方式就需要判断每种策略是否可以共享使用,它只是作为算法的实现。
        第二种是直接通过有状态的类,每次根据类型new一个新的策略类对象。这个就需要根据实际业务场景去做的判断。

框架的应用

策略模式在框架中也在一个很常见的地方体现出来了,而且大家肯定都有使用过。

那就是JDK中的线程池ThreadPoolExecutor
首先都是类似于这样定义一个线程池,里面实现线程池的异常策略。

这个线程池的异常策略就是用的策略模式的思想。
在源码中有RejectedExecutionHandler这个抽象异常策略接口,同时它也有四种拒绝策略。关系图如下:


这就是在框架中的体现了,根据自己的业务场景,合理的选择线程池的异常策略。


业务改造举例

在真实的业务场景中策略模式也还是应用很多的。

在社交电商中分享商品是一个很重要的环节,假设现在要我们实现一个分享图片功能,比如当前有 单商品、多商品、下单、会场、邀请、小程序链接等等多种分享场景。


针对上线这个流程图先用if else语句做一个普通业务代码判断,就像下面的这中方式:


public class SingleItemShare {
    // 单商品
    public void algorithm(String param) {
        System.out.println("当前分享图片是" + param);
    }
}
public class MultiItemShare {
    // 多商品
    public void algorithm(String param) {
        System.out.println("当前分享图片是" + param);
    }
}
public class OrderItemShare {
    // 下单
    public void algorithm(String param) {
        System.out.println("当前分享图片是" + param);
    }
}
public class ShareFactory {

    public static void main(String[] args) throws Exception {
        Integer shareType = 1;
       // 测试业务逻辑
        if (shareType.equals(ShareType.SINGLE.getCode())) {
            SingleItemShare singleItemShare = new SingleItemShare();
            singleItemShare.algorithm("单商品");
        } else if (shareType.equals(ShareType.MULTI.getCode())) {
            MultiItemShare multiItemShare = new MultiItemShare();
            multiItemShare.algorithm("多商品");
        } else if (shareType.equals(ShareType.ORDER.getCode())) {
            OrderItemShare orderItemShare = new OrderItemShare();
            orderItemShare.algorithm("下单");
        } else {
            throw new Exception("未知分享类型");
        }
        // .....省略更多分享场景
    }

    enum ShareType {
        SINGLE(1, "单商品"),
        MULTI(2, "多商品"),
        ORDER(3, "下单");
        /**
         * 场景对应的编码
         */
        private Integer code;
        /**
         * 业务场景描述
         */
        private String desc;
        ShareType(Integer code, String desc) {
            this.code = code;
            this.desc = desc;
        }
        public Integer getCode() {
            return code;
        }
       // 省略 get set 方法
    }
}




这里大家可以看到每新加一种分享类型,就需要加一次if else 判断,当如果有十几种场景的时候那代码整体就会非常的长,看起来给人的感觉也不是很舒服。

接下来就看看如何用策略模式进行重构:

public interface ShareStrategy {
    // 定义分享策略执行方法
    void shareAlgorithm(String param);
}

public class OrderItemShare implements ShareStrategy {
    @Override
    public void shareAlgorithm(String param) {
        System.out.println("当前分享图片是" + param);
    }
}

// 省略 MultiItemShare以及SingleItemShare策略

// 分享工厂
public class ShareFactory {
        // 定义策略枚举
    enum ShareType {
        SINGLE("single", "单商品"),
        MULTI("multi", "多商品"),
        ORDER("order", "下单");
        // 场景对应的编码
        private String code;
       
        // 业务场景描述
        private String desc;
        ShareType(String code, String desc) {
            this.code = code;
            this.desc = desc;
        }
        public String getCode() {
            return code;
        }
       // 省略 get set 方法
    }
        // 定义策略map缓存
    private static final Map<String, ShareStrategy> shareStrategies = new       HashMap<>();
    static {
        shareStrategies.put("order", new OrderItemShare());
        shareStrategies.put("single", new SingleItemShare());
        shareStrategies.put("multi", new MultiItemShare());
    }
    // 获取指定策略
    public static ShareStrategy getShareStrategy(String type) {
        if (type == null || type.isEmpty()) {
            throw new IllegalArgumentException("type should not be empty.");
        }
        return shareStrategies.get(type);
    }
    
    public static void main(String[] args) {
        // 测试demo
        String shareType = "order";
        ShareStrategy shareStrategy = ShareFactory.getShareStrategy(shareType);
        shareStrategy.shareAlgorithm("order");
        // 输出结果:当前分享图片是order
    }
}




这里策略模式就已经改造完了。在client请求端,根本看不到那么多的if else判断,只需要传入对应的策略方式即可,这里我们维护了一个策略缓存map,在直接调用的ShareFactory获取策略的时候就直接是从换种获取策略类对象。

这就已经达到了行为解偶的思想。同时也避免了长串的if else 判断。

优点:

        算法策略可以自由实现切换
        扩展性好,加一个策略,只需要增加一个类

缺点:

        策略类数量多
        需要维护一个策略枚举,让别人知道你当前具有哪些策略

总结

以上就讲完了策略模式,整体看上去其实还是比较简单的,还是那句话学习设计模式我们还是要学习每种设计模式的思想,任何一种设计模式存在即合理。当然也不要因为设计模式而设计代码,那样反而得不偿失。

  • 0
    感动
  • 0
    路过
  • 0
    高兴
  • 0
    难过
  • 0
    搞笑
  • 0
    无聊
  • 0
    愤怒
  • 0
    同情
热度排行
友情链接