策略模式 – 设计模式之行为模式

策略模式 – 设计模式之行为模式

目录

定义:

类图:

例子:

类图:

抽象的策略角色: IDiscount

具体策略角色1 OrdinaryStrategy

具体策略角色2 PlatinumStrategy

具体策略角色3 GoldStrategy

封装角色  DiscountStrategyContext

测试; DiscountTest

优化1:结合工厂方法

枚举类: UserTypeEnum

抽象的策略角色: IDiscount

具体策略角色1 OrdinaryStrategy

具体策略角色2 PlatinumStrategy

具体策略角色3 GoldStrategy

工厂方法类  DiscountStrategyFactory

测试; DiscountFactoryTest

优化2: 使用静态工厂,动态获取类

动态实例化类: SpringUtils

抽象的策略角色: IDiscount

具体策略角色1 OrdinaryStrategy

具体策略角色2 PlatinumStrategy

具体策略角色3 GoldStrategy

工厂方法类  DiscountStrategyFactory

封装角色; DiscountStrategyServiceContext

测试; DisountApplicationTests

总结:


 

定义:

 Define a family of algorithms, encapsulate each one, and make them interchangeable.(定义一组算法,将每个算法都封装起来,并且使它们之间可以互换)

定义了算法家族,分别封装起来,让它们之间可以相互替换,此模式算法的变化,不会影响到使用算法的用户。

 

类图:

 

 

 

例子:

用常见的购物场景,普通的不打折,白金会员打8折,铂金会员打6折

 

类图:

 

抽象的策略角色: IDiscount

public interface IDiscount {
    double compute(double money);
}

 

具体策略角色1 OrdinaryStrategy

public class OrdinaryStrategy implements IDiscount {

    @Override

    public double compute(double money) {

        System.out.println("普通会员不打折");

        System.out.println("积分是1%");

        return money;

    }

 }

 

具体策略角色2 PlatinumStrategy

public class PlatinumStrategy implements IDiscount {

    @Override

    public double compute(double money) {

        System.out.println("白金会员 优惠50元,再打7折");

        System.out.println("积分是5%");

        return (money - 50) * 0.7;

    }

}

 

具体策略角色3 GoldStrategy

public class GoldStrategy implements IDiscount {

    @Override

    public double compute(double money) {

        System.out.println("黄金会员 优惠50元,再打6折");

        System.out.println("积分是10%");

        return (money - 50)*0.6;

    }

}

 

封装角色  DiscountStrategyContext

public  class DiscountStrategyContext {

    private IDiscount discountStrategy;


    /**

     * 设置策略接口

     * @param discountHandleStrategy

     */

    public void setDiscountHandleStrategy(IDiscount discountHandleStrategy) {

        this.discountStrategy = discountHandleStrategy;

    }



    public void computeMoney(double money) {

        if (discountStrategy != null) {

            double compute = discountStrategy.compute(money);

            System.out.println(" pay "+ compute);

        }

    }

}

 

测试; DiscountTest

public class DiscountTest {

    public static void main(String[] args) {

        IDiscount discountStrategy = new OrdinaryStrategy();

        DiscountStrategyContext discountStrategyContext = new DiscountStrategyContext();

        discountStrategyContext.setDiscountHandleStrategy(discountStrategy);

        discountStrategyContext.computeMoney(100);

    }

}

 

结果:

普通会员不打折

积分是1%

     pay 100.0

思考: 在使用策略模式的时候,得先知道是哪个策略,还不是得if-else 进行判断,具体使用哪个策略。这个要怎么进行优化呢?只要知道一个名字就可以了,传递相关的数字或是名字进来,反馈一个结果,这才是想要的。

传递名字: 考虑用枚举,如例子中,三种会员的类型,相对固定。

对各个策略进行集中处理,考虑用工厂方法模式来实现策略类的声明。要知道策略的名称,接口那需要添加一个获取类型的方法。

 

优化1:结合工厂方法

 

枚举类: UserTypeEnum

public enum UserTypeEnum {

    COMMON_USER("COMMON"), PLATINUM_VIP("PLATINUM"),  GOLD_VIP("GOLD");
    String type;



    public String getType() {

        return type;

    }



    UserTypeEnum(String type) {

        this.type = type;

    }



    public static UserTypeEnum matchType(String type) {

        for (UserTypeEnum enumType : UserTypeEnum.values()) {

            if (enumType.type == type) {

                return enumType;

            }

        }

        return UserTypeEnum.COMMON_USER;

    }

}

 

抽象的策略角色: IDiscount

public interface IDiscount {
    double compute(double money);

// 用于匹配类型

 String getType();

}

 

具体策略角色1 OrdinaryStrategy

public class OrdinaryStrategy implements IDiscount { 

    @Override

    public double compute(double money) {

        System.out.println("普通会员不打折");

        System.out.println("积分是1%");

        return money;

    }



    @Override

    public String getType() {

        return UserTypeEnum.COMMON_USER.getType();

    }


}

 

具体策略角色2 PlatinumStrategy

public class PlatinumStrategy implements IDiscount {

    @Override

    public double compute(double money) {

        System.out.println("白金会员 优惠50元,再打7折");

        System.out.println("积分是5%");

        return (money - 50) * 0.7;

    }



    @Override

    public String getType() {

        return UserTypeEnum.PLATINUM_VIP.getType();

    }

}

 

具体策略角色3 GoldStrategy

public class GoldStrategy implements IDiscount {

    @Override

    public double compute(double money) {

        System.out.println("黄金会员 优惠50元,再打6折");

        System.out.println("积分是10%");

        return (money - 50)*0.6;

    }


    @Override

    public String getType() {

        return UserTypeEnum.GOLD_VIP.getType();

    }

}

 

 

工厂方法类  DiscountStrategyFactory

public class DiscountStrategyFactory {

    private Map<String, IDiscount> map;

    private DiscountStrategyFactory() {



        List<IDiscount> strategies = new ArrayList<>();

        strategies.add(new OrdinaryStrategy());

        strategies.add(new GoldStrategy());

        strategies.add(new GoldStrategy());

        strategies.add(new PlatinumStrategy());



        // getType 主要在这边声明的时候用

        map = strategies.stream()

                .collect(Collectors.toMap(IDiscount::getType, strategy -> strategy, (x, y) -> x));

    }



    public static class Holder {

        private static DiscountStrategyFactory instance = new DiscountStrategyFactory();

    }



    public static DiscountStrategyFactory getInstance() {

        return Holder.instance;

    }



    public IDiscount getIDiscountByType(String type) {

        return map.get(type);

    }

}

 

或是用静态的方式,直接map,这样就不用声明getType() 和实现这个方法了

 DiscountStrategyFactoryStatic:

public class DiscountStrategyFactoryStatic {

    public static Map<String,IDiscount> DICOUNT_TYPE = new HashMap<>();

    static {
        DICOUNT_TYPE.put("COMMON",new OrdinaryStrategy());
        DICOUNT_TYPE.put("PLATINUM",new GoldStrategy());
        DICOUNT_TYPE.put("GOLD",new PlatinumStrategy());
    }

    public static class Holder {
        private static DiscountStrategyFactoryStatic instance = new DiscountStrategyFactoryStatic();
    }

    public static DiscountStrategyFactoryStatic getInstance() {
        return Holder.instance;
    }

    public IDiscount getIDiscountByType(String type) {
        return DICOUNT_TYPE.get(type);
    }
}

测试; DiscountFactoryTest

public class DiscountFactoryTest {


    private static double getResult(long money, String type) {

        if (money < 1000) {

            return money;

        }


        IDiscount strategy = DiscountStrategyFactory.getInstance().getIDiscountByType (type);


        if (strategy == null) {

            throw new IllegalArgumentException("please input right type");

        }


        return strategy.compute(money);

    }


    public static void main(String[] args) {

        String type = "GOLD";

        UserTypeEnum userTypeEnum = UserTypeEnum.matchType(type);

        System.out.println(getResult(3300, userTypeEnum.getType()));

        System.out.println(getResult(2300, "PLATINUM"));

    }

}

 

结果:

黄金会员 优惠50元,再打6折

积分是10%

1950.0



白金会员 优惠50元,再打7折

积分是5%

1575.0

 

这就达到了想要的要求。输入一个名字,一个价格,就可以得到结果。

 

优化2: 使用静态工厂,动态获取类

 

动态实例化类: SpringUtils

@Component

public class SpringUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;


    @Override

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

        SpringUtils.applicationContext = applicationContext;

    }


    public static Object getBean(String name) {

        return applicationContext.getBean(name);

    }


    public static <T> T getBean(Class<T> clazz) {

        return applicationContext.getBean(clazz);

    }

}

 

抽象的策略角色: IDiscount

public interface IDiscount {
    double compute(double money);
}

 

具体策略角色1 OrdinaryStrategy

@Service
public class OrdinaryStrategy implements IDiscount {

    @Override

    public double compute(double money) {

        System.out.println("普通会员不打折");

        System.out.println("积分是1%");

        return money;

    }

}

 

具体策略角色2 PlatinumStrategy

@Service
public class PlatinumStrategy implements IDiscount {

    @Override

    public double compute(double money) {

        System.out.println("白金会员 优惠50元,再打7折");

        System.out.println("积分是5%");

        return (money - 50) * 0.7;

    }


}

 

具体策略角色3 GoldStrategy

@Service
public class GoldStrategy implements IDiscount {

    @Override

    public double compute(double money) {

        System.out.println("黄金会员 优惠50元,再打6折");

        System.out.println("积分是10%");

        return (money - 50)*0.6;

    }


}

 

工厂方法类  DiscountStrategyFactory

@Service

public class DiscountStrategyServiceFactory {


    private static Map<String,String> DICOUNT_TYPE = new HashMap<>();


    static {

        DICOUNT_TYPE.put("COMMON","goldStrategyService");

        DICOUNT_TYPE.put("PLATINUM","platinumStrategyService");

        DICOUNT_TYPE.put("GOLD","goldStrategyService");

    }


    public IDiscount getDiscountService(String type){

        return (IDiscount)SpringUtils.getBean(DICOUNT_TYPE.get(type));

    }


}

 

这边主要用SpringUtils获取bean的方式,实例化type对应的类

 

封装角色; DiscountStrategyServiceContext

@Service

public class DiscountStrategyServiceContext {

    @Resource

    private  DiscountStrategyServiceFactory discountStrategyServiceFactory;


    private double getResult(long money, String type) {

        if (money < 1000) {

            return money;

        }



        IDiscount strategy = discountStrategyServiceFactory.getDiscountService(type);



        if (strategy == null) {

            throw new IllegalArgumentException("please input right type");

        }



        return strategy.compute(money);

    }


    public void testResult() {

        System.out.println(getResult(3300, "GOLD"));

        System.out.println(getResult(2300, "PLATINUM"));

    }


}

 

 

 

测试; DisountApplicationTests

@RunWith(SpringRunner.class)

@SpringBootTest
public class DisountApplicationTests {



   @Autowired

   private DiscountStrategyServiceContext discountStrategyServiceContext;



   @Test

   public void testResult() {

      discountStrategyServiceContext.testResult();

   }

 

}
PS:这个是在springBoot项目里面的,启动后 注入@Service,初始化实例

结果:

黄金会员 优惠50元,再打6折

积分是10%

1950.0

白金会员 优惠50元,再打7折

积分是5%

1575.0

 

总结:

单纯用策略模式,并不能避免使用多重条件判断,结合枚举和工厂方法模式可以解决 问题,只通过一个名字或是数字,匹配到对应的策略。

策略模式的重点就是封装角色,它是借用了代理模式的思路,大家可以想想,它和代理模式有什么差别,差别就是策略模式的封装角色和被封装的策略类不用是同一个接口,如果是同一个接口那就成为了代理模式。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

天狼1222

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值