当前位置 博文首页 > 韩超的博客 (hanchao5272):设计模式-策略模式-以购物车的支付策

    韩超的博客 (hanchao5272):设计模式-策略模式-以购物车的支付策

    作者:[db:作者] 时间:2021-09-05 16:14

    超级链接: Java常用设计模式的实例学习系列-绪论

    参考:《HeadFirst设计模式》


    1.关于策略模式

    策略模式是一种行为模式。

    策略模式:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。

    如果某种行为拥有多种运作方式,那么把这种行为视为一种策略,把这些运作方式视为策略实现,这些策略实现之间可以相互替换。

    这样,行为调用方就可以在运行时,根据不同的需求,将相应的策略实现当做参数,以达到行为按照某种方式运作的目的。

    本文以购物车的支付策略为场景来学习策略模式

    • 每个商品都有名称和价钱。
    • 购物车可以添加多个商品。
    • 购物车支付方式暂时只支持支付宝和微信,但是后期可能会增减更多支付方式。

    2.关于商品

    由于本文的关注对象是设计模式,所以这里直接列出商品的代码。

    商品:Goods

    /**
     * <p>商品</P>
     *
     * @author hanchao
     */
    @Setter
    @Getter
    @AllArgsConstructor
    public class Goods {
        /**
         * 商品名称
         */
        private String name;
    
        /**
         * 商品价格
         */
        private Float price;
    }
    

    3.不采用策略模式的购物车

    3.1.代码

    购物车:OrdinaryShoppingCart

    /**
     * <p>购物车(普通版本)</P>
     *
     * @author hanchao
     */
    @Slf4j
    public class OrdinaryShoppingCart {
        /**
         * 商品列表
         */
        private List<Goods> goodsList;
    
        public OrdinaryShoppingCart() {
            goodsList = new ArrayList<>();
        }
    
        /**
         * 添加商品
         */
        public OrdinaryShoppingCart addGoods(Goods goods) {
            goodsList.add(goods);
            return this;
        }
    
        /**
         * 计算总价
         */
        public float totalCost() {
            return goodsList.stream().map(Goods::getPrice).reduce(Float::sum).orElse(0f);
        }
    
        /**
         * 通过支付宝支付
         */
        public void payWithAlipay() {
            log.info("通过支付宝支付了" + totalCost() + "元.");
        }
    
        /**
         * 通过微信支付
         */
        public void payWithWeChat() {
            log.info("通过微信支付了" + totalCost() + "元.");
        }
    }
    
    • 因为有多种支付方式,所以每种支付方式分表编写了一个方法。

    测试代码:ShoppingCartDemo

    /**
     * <p>购物车场景测试</P>
     *
     * @author hanchao
     */
    public class ShoppingCartDemo {
        public static void main(String[] args) {
            //购物车(普通版本)
          	//张三的购物行为
            new OrdinaryShoppingCart()
                    .addGoods(new Goods("一箱牛奶", 34.55f))
                    .addGoods(new Goods("一瓶白酒", 250.50f))
                    .payWithAlipay();
    
          	//李四的购物行为
            new OrdinaryShoppingCart()
                    .addGoods(new Goods("一箱牛奶", 34.55f))
                    .addGoods(new Goods("一瓶啤酒", 3.50f))
                    .payWithWeChat();
        }
    }
    

    运行结果:

    2019-07-02 15:53:48,424  INFO [main-1] pers.hanchao.designpattern.strategy.ordinary.OrdinaryShoppingCart:44 - 通过支付宝支付了285.05. 
    2019-07-02 15:53:48,429  INFO [main-1] pers.hanchao.designpattern.strategy.ordinary.OrdinaryShoppingCart:51 - 通过微信支付了38.05. 
    

    3.2.分析

    优点:

    • 实现简单:代码逻辑很简单,并且只需要编写一个类即可。

    缺点:

    • 扩展性差,每增减一种支付方式,都需要修改OrdinaryShoppingCart,违背了设计模式的开放-封闭原则(OCP,对扩展开放,对修改关闭)。
    • 可复用低,每种支付方式都采用不同的方法命名。

    4.采用策略模式的购物车

    4.1.代码

    策略模式的关键在于:将行为及其运作方式抽象为策略和策略实现。对于本场景而言,

    • 支付就是一种行为,可以将其视为一种策略,即:支付策略。
    • 支付宝支付微信支付都是支付行为的不同运作方式,可以分别将其视为一种策略实现。

    支付策略:PayStrategy

    /**
     * <p>支付策略</P>
     *
     * @author hanchao
     */
    public interface PayStrategy {
        /**
         * 支付
         *
         * @param cost 支付金额
         */
        void pay(Float cost);
    }
    

    支付策略实现一:支付宝

    /**
     * <p>支付宝支付策略</P>
     *
     * @author hanchao
     */
    @Slf4j
    public class AliPayStrategy implements PayStrategy {
        @Override
        public void pay(Float cost) {
            log.info("通过支付宝支付了" + cost + "元.");
        }
    }
    

    支付策略实现二:微信

    /**
     * <p>微信支付策略</P>
     *
     * @author hanchao
     */
    @Slf4j
    public class WeChatPayStrategy implements PayStrategy {
        @Override
        public void pay(Float cost) {
            log.info("通过微信支付了" + cost + "元.");
        }
    }
    

    购物车(策略模式版本):StrategyShoppingCart

    /**
     * <p>购物车(策略模式版本)</P>
     *
     * @author hanchao
     */
    @Slf4j
    public class StrategyShoppingCart {
    
        /**
         * 商品列表
         */
        private List<Goods> goodsList;
    
        /**
         * 支付策略
         */
        private PayStrategy payStrategy;
    
        public StrategyShoppingCart() {
            goodsList = new ArrayList<>();
        }
    
        /**
         * 添加商品
         */
        public StrategyShoppingCart addGoods(Goods goods) {
            goodsList.add(goods);
            return this;
        }
    
        /**
         * 计算总价
         */
        public float totalCost() {
            return goodsList.stream().map(Goods::getPrice).reduce(Float::sum).orElse(0f);
        }
    
        /**
         * 选择支付策略
         */
        public StrategyShoppingCart setPayStrategy(PayStrategy payStrategy) {
            this.payStrategy = payStrategy;
            return this;
        }
    
        /**
         * 支付
         */
        public void pay() {
            if (Objects.isNull(payStrategy)) {
                throw new IllegalStateException("未选择支付策略");
            } else {
                payStrategy.pay(totalCost());
            }
        }
    }
    
    • 策略(抽象类/接口)PayStrategy作为客户端StrategyShoppingCart的成员变量,如此才能承载不同的策略实现。
    • 提供策略实现的setter方法setPayStrategy(PayStrategy payStrategy),为策略实现的切换提供入口。

    测试代码:ShoppingCartDemo

    /**
     * <p>购物车场景测试</P>
     *
     * @author hanchao
     */
    public class ShoppingCartDemo {
        public static void main(String[] args) {
            //购物车(策略模式版本)
            //王五的购物行为
            new StrategyShoppingCart()
                    .addGoods(new Goods("一箱牛奶", 34.55f))
                    .addGoods(new Goods("一瓶白酒", 250.50f))
                    .setPayStrategy(new AliPayStrategy()).pay();
    
            //赵六的购物行为
            new StrategyShoppingCart()
                    .addGoods(new Goods("一箱牛奶", 34.55f))
                    .addGoods(new Goods("一瓶啤酒", 3.50f))
                    .setPayStrategy(new WeChatPayStrategy()).pay();
        }
    }
    

    运行结果:

    2019-07-02 17:47:07,309  INFO [main-1] pers.hanchao.designpattern.strategy.strategy.strategy.impl.AliPayStrategy:15 - 通过支付宝支付了285.05. 
    2019-07-02 17:47:07,310  INFO [main-1] pers.hanchao.designpattern.strategy.strategy.strategy.impl.WeChatPayStrategy:15