设计模式之策略模式

本文详细介绍了策略模式的概念,通过皇上选妃和支付场景的例子,解释了如何在Java和Spring项目中实现策略模式。文章指出,策略模式提供了一种管理算法族的方式,避免了多重条件选择语句,但可能会导致较多的具体策略类产生。

一句话总结

我有选择恐惧症 你别让我一个一个挑 我给你说需求 你帮我挑好

选择恐惧症

  • 选择恐惧症

选择恐惧症 说明了能选择的不止一个 (对应的策略不止一个)
每一个策略对应一个类

  • 我给你说需求

这个地方我刚开始也不理解 刚开始学习的时候就知道需要那个策略直接NEW 就行了
我怎么知道该New 那一个 难道要if else 判断 如果是这样 那还用啥策略模式?
这个时候你会想到 就算 判断 是不是有个判断的依据 如 下图 这里的paymentType
不就是我要的需求吗 ?
我给你个paymentType 你给我个类不就行了

    if ("支付宝".equals(paymentType)) {

        } else if ("微信".equals(paymentType)) {
    
        }
  • 你帮我挑好

这里的你 该如何定义类?
上文提到的一对一的关系是不是想到了 map (还有人用枚举类)
如果你是spring的项目 也可以用applicationContext 获取不同的bean对象(下面会有案例)

这样一分析是不是策略模式的主要角色都出来了。

抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
具体策略(Concrete Strategy)类:(上文中的具体的选择)实现了抽象策略定义的接口,提供具体的算法实现。
环境(Context)类:(上文中的你)持有一个策略类的引用,最终给客户端调用。

类图

在这里插入图片描述
细心的小伙伴会发现 这和状态模式类图很像如下图
这不是像简直一摸一样 这里先不讨论他俩的区别 详细的看https://www.runoob.com/w3cnote/state-vs-strategy.html
在这里插入图片描述

策略模式之皇上选妃

抽象策略(Strategy)类

/**
 * 抽象妃子类
 */
public interface ImperialConcubine {
    void exhibition();//妃子展示才艺
}

具体策略(Concrete Strategy)类

/**
 * 身材好的
 */
public class Figure implements ImperialConcubine {
    private String name;
    private String characteristic;

    public Figure(String name, String characteristic) {
        this.name = name;
        this.characteristic = characteristic;
    }

    @Override
    public void exhibition() {
        System.out.println(this.name + "低头不见脚尖");
    }
}
/**
 * 将军家女儿
 * 个之高 身材魁梧 会武功
 */
public class Hight implements ImperialConcubine{
    private String name;
    private String characteristic;

    public Hight(String name, String characteristic) {
        this.name = name;
        this.characteristic = characteristic;
    }

    @Override
    public void exhibition() {
        System.out.println(this.name+"飞檐走壁,");
    }
}
/**
 * 漂亮贤惠的妃子身材不好个子不高
 */
public class Pretty implements ImperialConcubine {
    private String name;
    private String characteristic;

    public Pretty(String name, String characteristic) {
        this.name = name;
        this.characteristic = characteristic;
    }

    @Override
    public void exhibition() {
        System.out.println(this.name+"一双丹凤三角眼两弯柳叶吊梢眉");
    }
}

环境(Context)类

import java.util.HashMap;

public class eunuch {
    private HashMap<String, ImperialConcubine> hashMap = new HashMap();

    public eunuch() {
        hashMap.put("hight", new Hight("杨胜男", "个子高"));
        hashMap.put("figure", new Figure("鱼幼微", "身材好"));
        hashMap.put("pretty", new Pretty("花仙子", "漂亮"));
    }

    public ImperialConcubine getImperialConcubine(String type) {
        return this.hashMap.get(type);
    }
}

客户端调用

public class emperor {
    public static void main(String[] args) {
        /**
         * 天快黑了 皇上叫来了太监
         */
        eunuch eunuch = new eunuch();

        /**
         * 看惯了人间美女 想看看仙女
         */
        ImperialConcubine pretty = eunuch.getImperialConcubine("pretty");
        /**
         * 来吧展示
         */
        pretty.exhibition();
        /**
         * 夜深了
         */
        ImperialConcubine figure = eunuch.getImperialConcubine("figure");
        /**
         * 来吧展示
         */
        figure.exhibition();
    }
}

输出

花仙子一双丹凤三角眼两弯柳叶吊梢眉
鱼幼微低头不见脚尖

只是为了更好的让人理解 以上例子仅供参考

策略模式之付款spring版本

1、定义策略接口
定义一个策略接口,所有支付方式的接口。

public interface IPayment {

    /**
     * 支付
     * @param order
     * @return
     */
    PayResult pay(Order order);

}

订单信息类:

@Data
public class Order {

    /**
     * 金额
     */
    private int amount;

    /**
     * 支付类型
     */
    private String paymentType;

}

返回结果类:


@Data
@AllArgsConstructor
public class PayResult {

    /**
     * 支付结果
     */
    private String result;

}

2、定义各种策略
定义各种支付策略,微信支付、支付宝、云闪付等支付实现类都实现这个接口。

微信支付实现

@Service("WechatPay")
public class WechatPay implements IPayment {

    @Override
    public PayResult pay(Order order) {
        return new PayResult("微信支付成功");
    }

}

支付宝实现:

@Service("Alipay")
public class Alipay implements IPayment {

    @Override
    public PayResult pay(Order order) {
        return new PayResult("支付宝支付成功");
    }

}

云闪付实现:

@Service("UnionPay")
public class UnionPay implements IPayment {

    @Override
    public PayResult pay(Order order) {
        return new PayResult("云闪付支付成功");
    }

}

这里我把所有支付方式类都用 @Service 注解生成 Bean 放入 Spring Bean 容器中了,在使用策略的时候就不用 new 支付对象了,可以直接使用 Bean,这样更贴近业务。Spring 基础教程就不介绍了

3、使用策略
有的文章使用了枚举、HashMap 的方式来根据策略名称映射策略实现类 ,这样是没有问题,但在使用了 Spring 框架的项目还是有点多此一举,完全可以发挥 Spring 框架的优势,使用 Bean 名称就能找到对应的策略实现类了。

参考示例代码如下:

@RestController
public class PayService {

    @Autowired
    private ApplicationContext applicationContext;

    /**
     * 支付接口
     *
     * @param amount
     * @param paymentType
     * @return
     */
    @RequestMapping("/pay")
    public PayResult pay(@RequestParam("amount") int amount,
                         @RequestParam("paymentType") String paymentType) {
        Order order = new Order();
        order.setAmount(amount);
        order.setPaymentType(paymentType);
        if ("支付宝".equals(paymentType)) {

        } else if ("微信".equals(paymentType)) {

        }
        // 根据支付类型获取对应的策略 bean
        IPayment payment = applicationContext.getBean(order.getPaymentType(), IPayment.class);

        // 开始支付
        PayResult payResult = payment.pay(order);

        return payResult;
    }

}

看示例代码,我并没有像策略模式结构图中那样新建一个 Context 类持有策略接口,那是标准的策略模式,其实道理是一样的,关键是怎么施放策略。
测试一下:

http://localhost:8080/pay?amount=8800&paymentType=WechatPay

在这里插入图片描述
5.效果
优点:

1)提供了对开闭原则的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为

2)提供了管理相关的算法族的办法

3)提供了一种可以替换继承关系的办法,可以避免多重条件选择语句

4)提供了一种算法的复用机制,不同的环境类可以方便地复用策略类

缺点:

1)客户端必须知道所有的策略类,并自行决定使用哪一个策略类

2)将造成系统产生很多具体策略类

3)无法同时在客户端使用多个策略类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一叶一菩提魁

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

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

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

打赏作者

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

抵扣说明:

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

余额充值