栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

设计模式之策略模式

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

设计模式之策略模式

一句话总结

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

选择恐惧症

选择恐惧症

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

我给你说需求

这个地方我刚开始也不理解 刚开始学习的时候就知道需要那个策略直接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 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 {

    
    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;

    
    @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)无法同时在客户端使用多个策略类

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/704876.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号