策略模式详解附有代码案例分析(包含策略模式在源码中的应用以及代码示例)

策略模式

一、策略模式的概念与角色

(一)、策略模式的概念

​ 策略模式又叫做政策模式,它是将 定义的算法家族、分别封装起来,让他们之间可以互相替换,从而让算法的变化不会影响到使用算法的用户。属于行为型模式。

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

(二)、策略模式的角色

​ 1、上下文角色(Context):用来操作策略的上下文环境,屏蔽高层模块(客户端)对策略,算法的直接访问,封装可能存在的变化。

​ 2、抽象策略角色(Strategy):规定策略或算法的行为。

​ 3、具体策略角色(ConcreteStategy):具体的策略或算法实现。

二、策略模式的应用场景

​ 1、针对同一类型问题,有多种处理方式,每一种都能独立解决问题。

​ 2、算法需要自由切换场景。

​ 3、需要屏蔽算法规则的场景。

三、策略模式的通用写法

抽象策略类:Strategy

public interface Strategy {
    void algorithm();
}

具体策略类:ConcreteStrategyA

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

具体策略类:ConcreteStrategyB

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

上下文:Context

public class Context {
    private Strategy mStrategy;

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

    public void algorithm() {
        this.mStrategy.algorithm();
    }
}

测试类:

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

四、策略模式的支付案例代码示例

MsgResult:

public class MsgResult {

    private int code;
    private Object data;
    private String msg;

    public MsgResult(int code, Object data, String msg) {
        this.code = code;
        this.data = data;
        this.msg = msg;
    }

    @Override
    public String toString() {
        return "MsgResult{" +
                "code=" + code +
                ", data=" + data +
                ", msg='" + msg + '\'' +
                '}';
    }
}

Payment:

public abstract class Payment {

    public abstract String getName();

    public MsgResult pay(String uid, double amount) {
        if (queryBalance(uid) < amount) {
            return new MsgResult(500, "支付失败", "余额不足");
        }
        return new MsgResult(200, "支付成功", "交易成功,交易金额:" + amount);
    }

    protected abstract double queryBalance(String uid);
}

AliPay:

public class AliPay extends Payment {
    @Override
    public String getName() {
        return "支付宝";
    }

    @Override
    protected double queryBalance(String uid) {
        return 520;
    }
}

JdPay:

public class JdPay extends Payment {
    @Override
    public String getName() {
        return "京东支付";
    }

    @Override
    protected double queryBalance(String uid) {
        return 123;
    }
}

WeChatPay:

public class WeChatPay extends Payment {
    @Override
    public String getName() {
        return "微信支付";
    }

    @Override
    protected double queryBalance(String uid) {
        return 250;
    }
}

PayStrategy:

public class PayStrategy {
    public static final String ALI_PAY = "AliPay";
    public static final String JD_PAY = "JdPay";
    public static final String WECHAT_PAY = "WeChatPay";
    public static final String DEFAULT_PAY = "WeChatPay";

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

    static {
        strategy.put(ALI_PAY, new AliPay());
        strategy.put(JD_PAY, new JdPay());
        strategy.put(WECHAT_PAY, new WeChatPay());
    }

    public static Payment get(String payKey) {
        if (!strategy.containsKey(payKey)) {
            return strategy.get(DEFAULT_PAY);
        }
        return strategy.get(payKey);
    }
}

Order:

public class Order {
    private String uid;
    private String orderId;
    private double amount;

    public Order(String uid, String orderId, double amount) {
        this.uid = uid;
        this.orderId = orderId;
        this.amount = amount;
    }

    public MsgResult pay() {
        return pay(PayStrategy.DEFAULT_PAY);
    }

    public MsgResult pay(String payKey) {
        Payment payment = PayStrategy.get(payKey);
        System.out.println("本次交易使用:" + payment.getName());
        System.out.println("交易金额:" + amount);
        return payment.pay(uid, amount);
    }

}

测试类:

public class Test {
    public static void main(String[] args) {
        Order order = new Order("123", "234345345", 234);
        System.out.println(order.pay(PayStrategy.WECHAT_PAY));
    }
}

类图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YrJSvYRn-1602815599629)(C:\Users\huang\AppData\Roaming\Typora\typora-user-images\image-20201016101427241.png)]

五、策略模式在源码中的应用

比较器:Comparator接口——compare()方法就是一个策略抽象实现

public interface Comparator<T> {
    // ......省略中间代码
    int compare(T o1, T o2);

Arrays类中的parallelSort()方法边将Comparator作为参数传入作为排序策略

public class Arrays {
    
	// ...... 省略中间代码
    
    public static <T> void parallelSort(T[] a, int fromIndex, int toIndex,
                                        Comparator<? super T> cmp) {
        rangeCheck(a.length, fromIndex, toIndex);
        if (cmp == null)
            cmp = Arrays.NaturalOrder.INSTANCE;
        int n = toIndex - fromIndex, p, g;
        if (n <= MIN_ARRAY_SORT_GRAN ||
                (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
            TimSort.sort(a, fromIndex, toIndex, cmp, null, 0, 0);
        else
            new ArraysParallelSortHelpers.FJObject.Sorter<T>
                    (null, a,
                            (T[]) Array.newInstance(a.getClass().getComponentType(), n),
                            fromIndex, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
                            MIN_ARRAY_SORT_GRAN : g, cmp).invoke();
    }
    
    // ...... 省略中间代码
}

在TreeMap的构造方法中同样使用了

public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, 
	
	// ...... 省略中间代码
    
	public TreeMap(Comparator<? super K> comparator) {
        this.comparator = comparator;
    }
	
	// ...... 省略中间代码
}

六、策略模式的优缺点

(一)、优点

​ 1、策略模式符合开闭原则

​ 2、避免使用多重条件转移语句,例如:if…else…

​ 3、使用策略模式可以提高算法的保密性和安全性

(二)、缺点

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

​ 2、代码中会尝试非常多的策略类,增加维护难度

七、设计模式的相关博客文章链接

1、七大设计原则的简单解释(包含合成复用原则),简单理解、快速入门,具备案例代码

链接: 七大设计原则的简单解释(包含合成复用原则),简单理解、快速入门,具备案例代码.

2、工厂模式详解附有代码案例分析(简单工厂,工厂方法,抽象工厂)

链接: 工厂模式详解附有代码案例分析(简单工厂,工厂方法,抽象工厂).

3、单例模式详解及代码案例与应用场景(饿汉式单例模式、懒汉式单例模式、注册式单例模式)

链接: 单例模式详解及代码案例与应用场景(饿汉式单例模式、懒汉式单例模式、注册式单例模式).

4、原型模式详解附有代码案例分析(浅克隆和深克隆的相关解析)

链接: 原型模式详解附有代码案例分析(浅克隆和深克隆的相关解析).

5、建造者模式详解附有代码案例分析(包含建造者模式与工厂模式的区别分析)

链接: 建造者模式详解附有代码案例分析(包含建造者模式与工厂模式的区别分析).

6、门面模式详解附有代码案例分析

链接: 门面模式详解附有代码案例分析.

7、装饰者模式详解附有代码案例分析

链接: 装饰者模式详解附有代码案例分析.

8、享元模式详解附有代码案例分析(包含享元模式的源码应用分析——String中的享元模式应用、Integer中的享元模式应用)

链接: 享元模式详解附有代码案例分析(包含享元模式的源码应用分析——String中的享元模式应用、Integer中的享元模式应用).

9、组合模式详解附有代码案例分析(包含透明组合模式、安全组合模式的代码示例)

链接: 组合模式详解附有代码案例分析(包含透明组合模式、安全组合模式的代码示例).

10、桥接模式详解附有代码案例分析

链接: 桥接模式详解附有代码案例分析.

11、适配器模式详解附有代码案例分析(包含类适配器、对象适配器以及接口适配器的代码示例)

链接: 适配器模式详解附有代码案例分析(包含类适配器、对象适配器以及接口适配器的代码示例).

12、委派模式详解附有代码案例分析(包含委派模式在JDK中的源码示例解析)

链接: 委派模式详解附有代码案例分析(包含委派模式在JDK中的源码示例解析).

13、模板方法模式详解附有代码案例分析(包含模板方法模式重构JDBC操作业务代码示例)

链接: 模板方法模式详解附有代码案例分析(包含模板方法模式重构JDBC操作业务代码示例).

14、策略模式详解附有代码案例分析(包含策略模式在源码中的应用以及代码示例)

链接: 策略模式详解附有代码案例分析(包含策略模式在源码中的应用以及代码示例).

15、责任链模式详解附有代码案例分析(包含责任链模式与建造者模式的结合代码案例)

链接: 责任链模式详解附有代码案例分析(包含责任链模式与建造者模式的结合代码案例).

16、迭代器模式详解附有代码案例分析(包含迭代器模式的源码应用分析)

链接: 迭代器模式详解附有代码案例分析(包含迭代器模式的源码应用分析).

17、命令模式详解附有代码案例分析(包含命令模式的源码应用分析)

链接: 命令模式详解附有代码案例分析(包含命令模式的源码应用分析).

18、状态模式详解附有代码案例分析(包含状态模式与其他相关设计模式的对比)

链接: 状态模式详解附有代码案例分析(包含状态模式与其他相关设计模式的对比).

19、备忘录模式详解附有代码案例分析

链接: 备忘录模式详解附有代码案例分析.

20、中介者模式详解附有代码案例分析

链接: 中介者模式详解附有代码案例分析.

21、解释器模式详解附有代码案例分析

链接: 解释器模式详解附有代码案例分析.

22、观察者模式详解附有代码案例分析(包含观察者模式使用JDK方式实现)

链接: 观察者模式详解附有代码案例分析(包含观察者模式使用JDK方式实现).

23、访问者模式详解附有代码案例分析

链接: 访问者模式详解附有代码案例分析.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值