点外卖,让我想起了 策略模式【原创】

回复“000”获取大量电子书

本篇文章是设计模式系列的第三篇:

模板模式

单例模式

今天给大家分享的是策略模式,具体内容大纲如下:

生活案例

在这互联网时代,尤其是在城市中,有一帮骑着电瓶车,穿梭在大街小巷中,这帮人就是外卖小哥。

对于点外卖,我也点过不少。有一次,外卖下单的时候,我突然联想到了一个设计模式---策略模式

策略模式是个啥?

策略模式:英文为Strategy Pattern,是指定义了算法家族、分别封装起来,让他们之间可以相互替换,此设计模式让算法的变化不会影响到使用算法的用户。

英文

Define a family of algorithms,encapsulate each one,and make them interchangeable.

大致意思:定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。

在策略模式中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式

策略模式通用代码

java代码实现如下:

class Client {

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

//具体策略类 ConcreteStrategy
    static class ConcreteStrategyA implements IStrategy {

@Override
        public void algorithm() {
            System.out.println("Strategy A");
        }
    }

//具体策略类 ConcreteStrategy
    static class ConcreteStrategyB implements IStrategy {

@Override
        public void algorithm() {
            System.out.println("Strategy B");
        }
    }

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

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

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

从上面的通用代码,我们可以得知其UML图。

策略模式UML图

策略模式中的角色

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

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

策略模式优缺点

优点

  • 策略模式符合开闭原则
  • 避免使用多重转换语句,比如:if...elseswitch语句。
  • 使用策略模式可以提高算法的保密性和安全性

缺点

  • 客户端必须知道所有策略,并且自行决定使用哪一种策略
  • 代码中产生非常多的策略类,增加后期维护难度

策略模式使用场景

在日常开发中,策略模式适用于以下三种场景:

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

这个说起来,还是不太好理解。

下面,我们就来使用生活案例来实现,让大家知道策略模式到底是怎么使用的。

支付案例代码重构,三个版本

外面下单,选择支付方式的时候,我觉这个功能,我们可以模仿着使用策略模式来实现一下。下面我们通过三个版本的迭代来实现,很有意思的。

第一版

先定义一个抽象类Pay:

//定义抽象类,我们可以把一些共用功能放在抽象类里实现
//比如:可用余额和本次支付金额进行比较,统一返回“支付失败”
public abstract class  Pay {
    abstract  void doPay();
}

下面模拟三种支付方式:

public class AliPay extends Pay {
    @Override
    public void doPay() {
        System.out.println("使用支付宝支付");
    }
}
public class UnionPay extends Pay {
    @Override
    public void doPay() {
        System.out.println("使用银联支付");
    }
}
public class WechatPay extends Pay {
    @Override
    public void doPay() {
        System.out.println("使用微信支付");
    }
}

我们再来进行支付:

public class PayTest {
    public static void main(String[] args) {
        //把选择权交给了用户
        Order order = new Order(new WechatPay());
        order.pay();*
    }
}

运行结果:

使用微信支付

这样我们就使用策略模式实现了简单版本的支付,但是其中有个很不爽的地方,就是每次还得自己手工new一个支付方式的对象。鉴于此,我们对第一版进行重构。

第二版

前面的实现都不变,变化的是发起支付的时候,只要前端传一个key过来就可以了,实现如下:

public class PayTest {
    public static void main(String[] args) {

String payKey = "Wechat";
        Order order = null;
        //通过判断前端传过来的key,判断使用哪种支付方式
        if (payKey.equals("Ali")) {
            order = new Order(new AliPay());
        } else if (payKey.equals("Wechat")) {
            order = new Order(new WechatPay());
        } else if (payKey.equals("union")) {
            order = new Order(new UnionPay());
        }else {
            //给出一个默认方式
            order = new Order(new WechatPay());
        }
        order.pay();
    }
}

运行结果

使用微信支付

这样我们就实现了,通过前端传过来的key,然后选出对应的支付方式。但是问题又来了,如果支付方式不断增多,那这里的if...else岂不是会越来越多吗?后续维护成本不是越来越大吗?

于是,第三版就有了。

第三版

在第二版中,会出现大量的if...else,会给后续的代码维护带来不便,于是在这一版中,我们对其进行重构,引入了注册式单例模式。

import java.util.HashMap;
import java.util.Map;

public enum PayStrategyEnum {
    ALI_PAY("Ali"),
    WECHAT_PAY("Wechat"),
    UNION_PAY("union"),
    //默认使用微信支付
    DEFAULT_PAY("Wechat");

private String key;

PayStrategyEnum(String key) {
        this.key = key;
    }

private static final Map<String, Pay> payKeyMap = new HashMap();

static {
        payKeyMap.put(ALI_PAY.key, new AliPay());
        payKeyMap.put(WECHAT_PAY.key, new WechatPay());
        payKeyMap.put(UNION_PAY.key, new UnionPay());
        payKeyMap.put(DEFAULT_PAY.key, new WechatPay());
    }

public static Pay getPay(String payKey) {
        if (!payKeyMap.containsKey(payKey)) {
            return payKeyMap.get(DEFAULT_PAY.key);
        }
        return payKeyMap.get(payKey);
    }
}

然后,在订单支付的时候就变成了这样了:

public class PayTest {
    public static void main(String[] args) { 
        String payKey = "Wechat"; 
        Order order = new Order(PayStrategyEnum.getPay(payKey));
        order.pay();
    }
}

运行结果

使用微信支付

这样,我们就成功的规避了大量的if...else了,爽歪歪!

其实,上面三个版本的代码,是不是觉得很爽,这就是设计模式的强大之处。

PS:关于上面的三个版本,其实我们还可以继续完善,继续重构,感兴趣的你可以去试试如何继续重构。

总结

好了,今天的策略模式就到这里。其实,设计模式在大多数情况下,是不会单独存在的,都是使用多种设计模式混合起来使用的。

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

最好记的案例:

我们可以使用不同的交通工具去北京玩

坐飞机、坐高铁、坐汽车、开车、骑车。方式很多,你想选哪一条就选那一条。

最后用一句话来总结策略模式:

条条大路通罗马

好了,今天的策略模式就分享到这里了。欢迎大家加我微信,一起探讨技术,相互学习。

推荐

限时免费下载,程序员必备书籍

283页!阿里P7大佬整理的后端知识库

免费获取《七周七并发模型》.pdf

Java 集合30个连环炮,难不难试试便知!

(0)

相关推荐

  • 通俗易懂系列 | 设计模式(五):策略模式

    介绍# 策略设计模式是行为设计模式之一.当我们为特定任务使用多个算法时,使用策略模式,客户端决定在运行时使用的实际实现. 策略模式的最佳示例之一是Collections.sort()采用Compara ...

  • PHP设计模式之策略模式

    PHP设计模式之策略模式 策略模式,又称为政策模式,属于行为型的设计模式. Gof类图及解释 GoF定义:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换.本模式使得算法可独立于使用它的 ...

  • [PHP小课堂]PHP设计模式之策略模式

    [PHP小课堂]PHP设计模式之策略模式 关注公众号:[硬核项目经理]获取最新文章 添加微信/QQ好友:[DarkMatterZyCoder/149844827]免费得PHP.项目管理学习资料

  • 设计模式之策略模式

    策略模式 Strategy Intro 策略模式(Strategy):它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的 Context. 策略模式是一种定 ...

  • 设计模式——策略模式

    什么是策略模式?策略模式属于对象的行为模式.其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换.策略模式使得算法可以在不影响到客户端的情况下发生变化.举个例子? ...

  • PHP设计模式—策略模式

    定义: 策略模式(Strategy):它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户. 结构: Strategy(策略类):定义所有支持的算法的公 ...

  • 设计模式(22) 策略模式

    在策略模式中,一个类的行为或算法可以在运行时动态更改. GOF对策略模式的描述为: Define a family of algorithms, encapsulate each one, and m ...

  • 设计模式-策略模式

    示例 策略模式是我们工作中比较常用的一个设计模式,但是初次理解起来可能会有点困难,因此我们还是先看一个例子,假设现在需要开发一个画图工具,画图工具中有钢笔,笔刷和油漆桶,其中,钢笔可以用于描边,但不能 ...

  • 详解JAVA面向对象的设计模式 (二)、策略模式

    策略模式 Strategy 介绍 在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改.这种类型的设计模式属于行为型模式. 在策略模式中,我们创建表示各种策略的对象和 ...

  • 策略模式

    有道无术,术可求 有术无道,止于术 一.策略模式的定义 先举一个例子来说:在网上购物的时候,有的时候会有一些打折的活动,可能会给你5元的优惠券,也有可能会给一张满减的优惠券,而无论给怎样的优惠券,到了 ...