写在前面
如果你正在为代码的可扩展性和可维护性感到烦恼,策略模式可以成为你的得力助手。本篇技术文章详细介绍了策略模式的核心原理和实战应用,帮助你解决在程序设计中所面临的挑战。无论你是初学者还是有一定经验的开发者,这篇文章都能够为你提供有益的知识和实用的技巧,值得一读!
前言
用于处理类或对象的组合的结构型的设计模式已经输出完毕:
从这篇文章开始来盘一盘行为型设计模式,那么行为型的设计模式有哪些呢?行为型模式是用于描述类或对象怎样交互以及怎样分配职责,共十一种,包括策略模式、模版方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
什么是策略模式
策略模式是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。策略模式的主要目的是将算法的行为和环境分开,将一系列算法封装在策略类中,并在运行时根据客户端的需求选择相应的算法。策略模式适用于需要使用多种算法,且算法之间可以相互替换的情况。在策略模式中,算法的变化不会影响到使用算法的客户端。
策略模式的核心原理
策略模式是一种行为设计模式,其核心原理是将可以相互替换的算法封装成独立的类,并使它们能够互相之间替换,以使得算法的变化独立于使用算法的客户端。
策略模式主要包括三个核心角色:
- Context(上下文):这个角色是策略模式中的重要组成部分,通常用于存储和传递策略对象,以及处理策略对象的交互逻辑。上下文对象在客户端的请求下,会调用合适的策略对象来执行相应的操作。
- Strategy(策略):这个角色通常是一个接口,用于定义各种策略对象的共同方法。具体策略对象实现这个接口,并包含具体的算法实现。策略对象不持有任何上下文对象的状态,这样保证了策略对象的可复用性。
- ConcreteStrategy(具体策略):这个角色是实现策略接口的具体类,包含了具体的算法实现。具体策略对象通常会持有上下文对象的状态,以便在执行算法时能够访问和修改这些状态。
这三个核心角色共同实现了策略模式的核心思想:将算法与使用算法的客户端分离,使算法可以独立于客户端而变化。
策略模式如何实现
需求描述
很多购物网站都有会员业务,不同等级的会员可以享受不同程度的优惠,这里假设某会员业务系统的会员等级有非会员、初级会员、中级会员、高级会员四个等级,其中非会员在支付的时候需要全额支付 ,初级会员可以享受8折优惠,中级会员可以享受7折优惠,高级会员可以享受5折优惠,如果需要写一个支付接口,需要怎么实现呢?
实现方案
类似这样的业务模型,是比较适合使用策略模式的,但是如果仅仅使用策略模式是没有办法在主业务流程中完全避免if else的判断的,如果从实际业务出发,可以把简单工厂模式和策略模式结合起来使用。策略模式只负责定义不同的优惠策略,而简单工厂模式,负责根据不同的会员,生产出不同的具体优惠策略。具体怎么做呢?
1、定义抽象的支付策略接口:PayStrategy.java;
java
/**
* 支付策略接口
*/
public interface PayStrategy {
/**
* 实际支付金额计算
* @param money
*/
Double compute(Double money);
}
2、定义具体的支付策略类:Level0Streategy.java、Level1Streategy.java、Level2Streategy.java、Level3Streategy.java
java
/**
* 非会员计费策略
*/
public class Level0Strategy implements PayStrategy{
@Override
public Double compute(Double money) {
System.out.println("非会员开始计费");
return money;
}
}
java
/**
* 初级会员计费策略
*/
public class Level1Strategy implements PayStrategy{
@Override
public Double compute(Double money) {
System.out.println("初级会员开始计费");
return money*0.8;
}
}
java
/**
* 中级会员计费策略
*/
public class Level2Strategy implements PayStrategy{
@Override
public Double compute(Double money) {
System.out.println("中级会员开始计费");
return money*0.7;
}
}
java
/**
* 高级会员计费策略
*/
public class Level3Strategy implements PayStrategy{
@Override
public Double compute(Double money) {
System.out.println("高级会员开始计费");
return money*0.5;
}
}
3、定义用于存储和传递策略的上下文:StreateContext.java
java
/**
* 支付策略上下文
*/
public class StrategyContent {
private PayStrategy payStrategy;
public StrategyContent(PayStrategy payStrategy) {
this.payStrategy = payStrategy;
}
/**
* 支付方法
* @param money
* @return
*/
public Double pay(Double money){
return this.payStrategy.compute(money);
}
}
4、定义策略工厂类,用于生产具体的策略:PayStreategyFactory.java
java
/**
* 策略工厂
*/
public class PayStrategyFactory {
public static PayStrategy getStrategy(Member member){
PayStrategy payStrategy;
switch (member.getLevel()){
case "初级":
payStrategy=new Level1Strategy();
break;
case "中级":
payStrategy=new Level2Strategy();
break;
case "高级":
payStrategy=new Level3Strategy();
break;
default:
payStrategy=new Level0Strategy();
break;
}
return payStrategy;
}
}
5、编写客户端:,模拟不同的用户进行支付:Test.java
java
@Data
@AllArgsConstructor
public class Member {
/**
* 会员姓名
*/
private String name;
/**
* 会员等级:非会员、初级、中级、高级
*/
private String level;
/**
* 支付金额
*/
private Double pay;
}
java
public class Test {
public static void main(String[] args) {
Member member = new Member("小明", "初级", 100.00);
PayStrategy strategy = PayStrategyFactory.getStrategy(member);
StrategyContent strategyContent = new StrategyContent(strategy);
Double pay = strategyContent.pay(member.getPay());
System.out.println(member.getName() + "应支付金额:" + member.getPay() + ",实际支付金额:" + pay);
member = new Member("小红", "中级", 100.00);
strategy = PayStrategyFactory.getStrategy(member);
strategyContent = new StrategyContent(strategy);
pay = strategyContent.pay(member.getPay());
System.out.println(member.getName() + "应支付金额:" + member.getPay() + ",实际支付金额:" + pay);
member = new Member("铁蛋", "高级", 100.00);
strategy = PayStrategyFactory.getStrategy(member);
strategyContent = new StrategyContent(strategy);
pay = strategyContent.pay(member.getPay());
System.out.println(member.getName() + "应支付金额:" + member.getPay() + ",实际支付金额:" + pay);
member = new Member("李刚", "非会员", 100.00);
strategy = PayStrategyFactory.getStrategy(member);
strategyContent = new StrategyContent(strategy);
pay = strategyContent.pay(member.getPay());
System.out.println(member.getName() + "应支付金额:" + member.getPay() + ",实际支付金额:" + pay);
}
}
策略模式的适用场景
- 不同业务逻辑:在同一个业务逻辑中,可能会存在不同的策略或算法。例如,在电商网站中,可以根据不同的促销策略对商品进行不同的定价。在这种情况下,可以使用策略模式来封装不同的促销策略,并在运行时根据需要选择合适的策略。
- 数据排序策略:在处理大量数据时,可能需要使用不同的排序算法。例如,冒泡排序、选择排序、插入排序和二叉树排序等。在这种情况下,可以使用策略模式来定义不同的排序策略,并在运行时根据需要选择合适的策略。
- 算法切换:在某些情况下,可能需要根据不同的条件切换不同的算法。例如,在进行实时计算时,可能需要根据不同的输入数据选择不同的计算算法。在这种情况下,可以使用策略模式来封装不同的算法,并在运行时根据需要选择合适的算法。
- 行为切换:在系统中,可能需要根据不同的条件切换不同的行为。例如,在一个游戏中,可能需要根据不同的关卡选择不同的游戏策略。在这种情况下,可以使用策略模式来封装不同的游戏策略,并在运行时选择合适的行为。
总之,策略模式的应用场景非常广泛,可以用于处理不同业务逻辑、数据排序、算法切换和行为切换等方面。通过使用策略模式,我们可以将算法或行为的变化和具体实现细节分离出来,使得代码更加灵活、易于维护和扩展。
总结
优点:
- 避免使用多重条件语句:策略模式通过使用策略类和上下文对象来避免使用多重条件语句,如if-else语句或switch-case语句。通过将算法的行为封装到策略类中,并在运行时根据客户端的需求选择相应的算法,策略模式使得代码更加简洁、易于维护和扩展。
- 提供可重用的算法族:策略模式通过定义抽象策略类和具体策略类,提供了一系列的算法实现。这些算法可以在不同的上下文中重复使用,通过组合和替换不同的策略对象来满足客户端的需求。
- 分离算法和客户端:策略模式将算法的实现和使用分离到具体的策略类和上下文对象中。客户端只需要与上下文对象进行交互,而不需要直接处理算法的实现细节。这种分离使得代码更加清晰、易于理解和维护。
- 支持对开闭原则的完美支持:策略模式可以在不修改原有代码的情况下,灵活地增加新的算法。通过定义新的策略类和上下文对象,可以轻松地将新的算法集成到现有系统中,满足新的需求。
- 将算法的使用放到环境类中:策略模式将算法的使用放到上下文对象中,而算法的实现则移到具体策略类中。这种分离使得代码更加清晰、易于管理和扩展。
- 客户端必须理解所有策略算法的区别:策略模式要求客户端必须理解所有可用的策略算法的区别,以便在适当的时候选择合适的算法。这可能增加了客户端的复杂性和学习成本。
缺点
- 可能导致过多的策略类:策略模式可能导致创建过多的策略类,每个算法都对应一个策略类。这可能会增加系统的复杂性和维护成本。
总之,策略模式是一种行为型设计模式,它通过封装一系列可重用的算法实现,并将它们组合到不同的上下文中,实现了算法的行为和使用的分离。这种模式使得代码更加灵活、易于维护和扩展,同时支持在不修改原有代码的情况下增加新算法,从而提高了代码的灵活性和可维护性。
写在最后
感谢您阅读我们的技术文章!这篇文章详细介绍了策略模式的核心原理和实战应用,对于程序设计中所面临的问题提出了有益的解决方案。如果您觉得这篇文章有价值,请帮忙点赞和收藏,让更多人看到并受益。您的支持是我不断前行的动力和鼓励。再次感谢您的阅读和支持,期待我们的下一次相遇!