栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

优雅代码之路-策略模式的优雅应用,不用再担心if...esle灾难

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

优雅代码之路-策略模式的优雅应用,不用再担心if...esle灾难

目录
  • 代码地址
  • 简介
  • 代码示例
  • 代码示例-2
  • Spring Boot示例
  • 总结

代码地址

https://gitee.com/nssnail/design-pattern/tree/master/%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F

简介

策略模式(Strategy Pattern )又叫也叫政策模式( Policy Pattern ),它是将定义的算法家族、分别封装起来,让它们之间可以互相替换,从而让算法的变化不会影响到使用算法的用户。属于行为型模式。

策略模式使用的就是面向对象的继承和多态机制,从而实现同一行为在不同场景下具备不同实现

策略模式可以解决在有多种算法相似的情况下,使用if…else或switch…case所带来的复杂性和臃肿性。在日常业务开发中,策略模式适用于以下场景∵

  1. 针对同一类型问题,有多种处理方式,每一种都能独立解决问题;
  2. 算法需要自由切换的场景;
  3. 需要屏蔽算法规则的场景。

类图如下

从UML类图中,我们可以看到,策略模式主要包含三种角色∶

  • **上下文角色( Context )**∶用来操作策略的上下文环境,屏蔽高层模块(客户端)对策略,算法的直接访问,封装可能存在的变化;
  • **抽象策略角色( Strategy ) **∶规定策略或算法的行为﹔
  • 具体策略角色( ConcreteStrategy ):具体的策略或算法实现。

白话文解释: 比如在生活中我们有很多种优惠策略,返现优惠,折扣优惠,优惠券抵扣优惠等,我们用户只需要直到选择哪种优惠策略就好,并不需要关注算法的实现

代码示例

IStrategy.java

//抽象策略类 Strategy
public interface IStrategy {
    void algorithm();
}

ConcreteStrategyA.java

//具体策略类 ConcreteStrategy
public class ConcreteStrategyA implements IStrategy {
    public void algorithm() {
        System.out.println("Strategy A");
    }
}

ConcreteStrategyB.java

//具体策略类 ConcreteStrategy
public class ConcreteStrategyB implements IStrategy {
    public void algorithm() {
        System.out.println("Strategy B");
    }
}

Context.java

//上下文环境
public class Context {
    private IStrategy mStrategy;

    public Context(IStrategy strategy) {
        this.mStrategy = strategy;
    }

    public void algorithm() {
        this.mStrategy.algorithm();
    }
}

Test.java

public class Test {
    public static void main(String[] args) {
        //选择一个具体策略
        IStrategy strategy = new ConcreteStrategyA();
        //来一个上下文环境
        Context context = new Context(strategy);
        //客户端直接让上下文环境执行算法
        context.algorithm();
    }
}

执行结果

Strategy A

但是这种方式是直接new对象后注入,并不能自行选择策略

代码示例-2

接下来我们模拟一个优惠策略的选择

DiscountStrategy.java

public interface DiscountStrategy {
    void doPromotion();
}

CashbackStrategy.java

public class CashbackStrategy implements DiscountStrategy {
    public void doPromotion() {
        System.out.println("返现策略");
    }
}

CouponStrategy.java

public class CouponStrategy implements DiscountStrategy {
    public void doPromotion() {
        System.out.println("优惠券抵扣策略");
    }
}

GroupbuyStrategy.java

public class GroupbuyStrategy implements DiscountStrategy {
    public void doPromotion() {
        System.out.println("拼团策略");
    }
}

EmptyStrategy.java

public class EmptyStrategy implements DiscountStrategy {
    public void doPromotion() {
        System.out.println("无优惠");
    }
}

这时候我们使用一个简单工厂来创建策略

DiscountStrategyFactory.java

public class DiscountStrategyFactory {

    private DiscountStrategyFactory(){};

    public static DiscountStrategy getStrategy(String name){
        if(name.equals("cashBack")){
            return new CashbackStrategy();
        }else if(name.equals("coupon")){
            return new CouponStrategy();
        }else if(name.equals("groupbuy")){
            return new GroupbuyStrategy();
        }else {
            return new EmptyStrategy();
        }
    }

}

Test.java

public class Test {

    public static void main(String[] args) {
        DiscountStrategy cashBack = DiscountStrategyFactory.create("cashBack");
        cashBack.doPromotion();
    }
}

执行结果:

返现策略

但是我们这样还是没有消除if…esle判断,接下来我们再优化下

添加DiscountConstant.java

public class DiscountConstant {

    
    public static final String CASH_BACK="cashBack";

    
    public static final String COUPON="coupon";

    
    public static final String GROUP_BY="groupBy";

    
    public static final String EMPTY="empty";

}

修改工厂类DiscountStrategyFactory.java

public class DiscountStrategyFactory {

    //策略容器
    private static Map PROMOTIONS=new HashMap();

    //设置单例
    private DiscountStrategyFactory(){};

    //初始化策略列表
    static {
        PROMOTIONS.put(DiscountConstant.CASH_BACK,new CashbackStrategy());
        PROMOTIONS.put(DiscountConstant.COUPON,new CouponStrategy());
        PROMOTIONS.put(DiscountConstant.GROUP_BY,new GroupbuyStrategy());
        PROMOTIONS.put(DiscountConstant.EMPTY,new EmptyStrategy());
    }


    //获取策略
    public static DiscountStrategy getStrategy(String name){
        DiscountStrategy strategy = PROMOTIONS.get(name);
        return strategy == null ? PROMOTIONS.get(DiscountConstant.EMPTY) : strategy;
    }

    //获取策略名称列表
    public static Set getPromotionKeys(){
        return PROMOTIONS.keySet();
    }

}

Test.java

public class Test {

    public static void main(String[] args) {

        //用户获取优惠策略列表
        Set promotionKeys = DiscountStrategyFactory.getPromotionKeys();
        System.out.println(promotionKeys);
        //用户根据策略列表选择策略
        DiscountStrategy cashBack = DiscountStrategyFactory.getStrategy("coupon");
        cashBack.doPromotion();
    }
}

这样我们就消除了if…else的判断,通过map的性质来获取策略

注:这里还能使用配置文件然后通过反射来获取策略,一样可以消除if...else,如一些缓存淘汰策略

Spring Boot示例

在spring中,我们可以将策略放入容器中

添加pom.xml依赖



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.1.7.RELEASE
         
    
    com.sise
    策略模式
    1.0-SNAPSHOT

    
        1.8
        UTF-8
        2.3.0.RELEASE
    

    
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
            org.springframework.boot
            spring-boot-starter-web
        
    

添加配置文件application.properties

server.port=9096
spring.application.name=demo

DiscountStrategy.java

public interface DiscountStrategy {
    String doPromotion();
}

CashbackStrategy.java

@Component(DiscountConstant.CASH_BACK)
public class CashbackStrategy implements DiscountStrategy {
    public String doPromotion() {
        return "返现策略";
    }
}

CouponStrategy.java

@Component(DiscountConstant.COUPON)
public class CouponStrategy implements DiscountStrategy {
    public String doPromotion() {
        return "优惠券抵扣策略";
    }
}

GroupbuyStrategy.java

@Component(DiscountConstant.GROUP_BY)
public class GroupbuyStrategy implements DiscountStrategy {
    public String doPromotion() {
        return "拼团策略";
    }
}

EmptyStrategy.java

@Component(DiscountConstant.EMPTY)
public class EmptyStrategy implements DiscountStrategy {
    public String doPromotion() {
        return "无优惠";
    }
}

TestController.java 测试接口类

@RestController
@RequestMapping("/test")
public class TestController {

    @Autowired
    private ApplicationContext applicationContext;

    @RequestMapping("/doPromotion/{strategy}")
    public String doPromotion(@PathVariable String strategy){
        DiscountStrategy bean = applicationContext.getBean(strategy, DiscountStrategy.class);
        if(ObjectUtils.isEmpty(bean)){
            bean=new EmptyStrategy();
        }
        return bean.doPromotion();
    }
}

接口测试 http://localhost:9096/test/doPromotion/cashBack

更换参数 http://localhost:9096/test/doPromotion/coupon

总结

1. 优点

(1)策略模式符合开闭原则。
(2)避免使用多重条件转移语句,如i…else…语句、switch语句
(3)使用策略模式可以提高算法的保密性和安全性。
2. 缺点

(1)客户端必须知道所有的策略,并且自行决定使用哪一个策略类。
(2)代码中会产生非常多策略类,增加维护难度。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/424027.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号