• 常用设计模式——策略模式


    策略模式是什么

    策略模式(Strategy):针对一组算法,将每一个算法封装起来,从而使得它们可以相互替换。

    比如我们一个软件的会员等级,每一个等级都会有对应的一些等级权益,那么每一个等级权益就对应一个策略

    结构

    策略模式的通用类图如下:
    在这里插入图片描述
    策略模式主要由这三个角色组成,环境角色(Context)、抽象策略角色(Strategy)和具体策略角色(ConcreteStrategy)

    1.上下文角色(Context):持有所有策略类的对象,可以根据策略提供相应的算法给客户端使用。
    2.抽象策略角色(Strategy):这是一个抽象角色,通常由一个接口或抽象类实现。此角色提供具体策略类所需的接口。
    3.具体策略角色(ConcreteStrategy):继承或实现了抽象策略,封装了相应的算法或行为。

    策略模式的优缺点

    优点
    (1)算法可以自由切换
    (2)避免使用多重条件判断
    (3)扩展性良好,增加一个策略只需实现接口即可

    缺点
    (1)策略类数量会增多,每个策略都是一个类,复用性很小
    (2)所有的策略类都需要对外暴露

    使用场景

    1、业务代码需要根据场景不同,切换不同的实现逻辑
    2、代码中存在大量 if else 逻辑判断

    实例

    下面使用策略模式实现会员不同等级的权益领取

    抽象策略角色:

    /**
     * 会员抽象策略
     */
    public interface MemberStrategy {
    
        /**
         * 领取会员福利
         */
        void getWeal();
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    具体策略角色:

    /**
     * 等级1的会员福利
     */
    @Component
    public class LV1MemberWeal implements MemberStrategy {
    
        @Override
        public void getWeal() {
            System.out.println("5元优惠券");
        }
        
    }
    
    /**
     * 等级2会员福利
     */
    @Component
    public class LV2MemberWeal implements MemberStrategy{
    
        @Override
        public void getWeal() {
            System.out.println("10元优惠券");
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    上下文角色:

    我们可以使用枚举加bean工厂来定义一个上下文角色,避免上下文角色的if-else

    策略枚举类

    策略枚举类用于获取bean容器中的策略类class

    /**
     * 策略枚举
     */
    public enum MemberEnum {
        LV1(LV1MemberWeal.class),
        LV2(LV2MemberWeal.class);
        ;
    
        private Class clazz;
    
        MemberEnum(Class clazz) {
            this.clazz = clazz;
        }
    
        public static Class getStrategyClass(String name){
            return MemberEnum.valueOf(name).clazz;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    使用ApplicationContext可以获取bean工厂中的实例,下面是对应工具类

    @Component
    public class ApplicationContextUtil implements ApplicationContextAware {
    
        private static ApplicationContext applicationContext;
    
        /**
         * 将ApplicationContext注入
         * @param applicationContext
         * @throws BeansException
         */
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
        }
    
        public static ApplicationContext getApplicationContext(){
            return applicationContext;
        }
    
        /**
         * 根据类型获取bean
         * @param clazz
         * @param 
         * @return
         */
        public static <T> T getBean(Class clazz){
            return (T) getApplicationContext().getBean(clazz);
        }
    
        /**
         * 根据名称获取bean
         * @param name
         * @param 
         * @return
         */
        public static  <T> T getBean(String name){
            return (T) getApplicationContext().getBean(name);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    上下文角色类

    /**
     * 会员上下文角色
     */
    @Component
    public class MemberStrategyContext {
    
        /**
         * 根据入参类型获取对应的策略类
         * @param type
         * @return
         */
        public MemberStrategy getMemberStrategy(String type){
            MemberStrategy memberStrategy = ApplicationContextUtil.getBean(MemberEnum.getStrategyClass(type));
            return memberStrategy;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    测试类

    RunWith(SpringRunner.class) //作用:让当前类在容器环境下进行测试
    @SpringBootTest(classes = DemoApplication.class)
    public class StrategyTest {
    
        @Autowired
        private MemberStrategyContext memberStrategyContext;
    
        @Test
        public void testStrategy(){
            //根据入参获取对应策略类
            MemberStrategy memberStrategy = memberStrategyContext.getMemberStrategy("LV2");
            //执行策略类的算法
            memberStrategy.getWeal();
    
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
  • 相关阅读:
    Maven项目转为SpringBoot项目
    Java基础知识点整理
    设计模式——22. 责任链模式
    【题解】同济线代习题一.6.1
    lenovo联想台式机 拯救者 刃7000-28ICBR(90KX)原装出厂Windows10系统镜像
    Mysql中事务是什么?有什么用?
    vue select选择下拉组织树,解决不出现横向滚动条
    操作系统 || 虚拟内存VM.未
    _IO_2_1_stdin_ 任意写及对 _IO_2_1_stdout_ 任意读的补充
    API接口随心搭,自由定制你的数据流
  • 原文地址:https://blog.csdn.net/qq_36551991/article/details/134248927