✨这里是第七人格的博客✨小七,欢迎您的到来~✨
🍅系列专栏:设计模式🍅
✈️本篇内容: 策略模式✈️
🍱本篇收录完整代码地址:gitee.com/diqirenge/d... 🍱
楔子
策略模式是一种行为型设计模式,其主要目标是根据运行时的需求选择对应的算法,而无需对客户端代码进行修改。这种模式将各种算法封装在抽象策略和具体策略类中,使得用户可以根据不同的需求选择具体的实现算法。例如,在一个支付系统中,可能会存在多种付款方式,如信用卡、借记卡和电子钱包等。在这种情况下,程序可以在运行时根据用户的选择来执行相应的支付操作。
策略模式的主要优点是提高了代码的复用性和可维护性,同时降低了系统的耦合度。通过使用策略模式,我们能够消除复杂的多重条件语句(说人话就是,可以使用策略类来消除大量的if-else)从而提高代码的可读性。然而,每个策略都需要一个单独的类,这可能会导致系统的类数量增加。
需求背景
我们现在有个活动,需要给用户发放福利,发放的福利可以是券、积分或者图文。现在让你来设计这个功能,你应该怎么设计呢?
分析设计
根据需求一把梭,我们可以创建一个名为Welfare的类,接着再创建一个枚举类型Type,用于表示福利的类型(券、积分或图文)。然后,我们可以在Welfare类中添加一个方法sendWelfare,该方法接受一个用户对象和一个福利类型作为参数,并根据福利类型执行相应的操作。这样虽然很快的完成了任务,但是对代码以后的拓展维护埋下了隐患。
所以我们尝试着优化它,首先,我们需要创建一个名为WelfareStrategy的接口,该接口包含一个名为sendWelfare的方法,用于发送福利。然后,我们可以为每种福利类型创建一个实现WelfareStrategy接口的具体策略类。接下来,我们需要创建一个名为WelfareContext的类,该类包含一个名为setStrategy的方法,用于设置当前的策略。在sendWelfare方法中,我们将调用当前策略的sendWelfare方法。
为了让客户端不用主动选择调用哪个策略,我们还可以创建一个名为WelfareFactory的工厂类,该类包含一个名为createWelfare的方法,用于创建不同类型的福利对象。然后,我们可以在WelfareContext类中使用WelfareFactory来创建福利对象。
UML图
根据分析设计,我们可以先画一个简单的UML图,后面通过UML图编码
模块名称
strategy
模块地址
模块描述
策略模式代码示例
代码实现
一、代码一把梭
1、定义公共类
java
/**
* 定义福利类型枚举
* 关注公众号【奔跑的码畜】,一起进步不迷路
*
* @author 第七人格
* @date 2023/12/25
*/
public enum Type {
COUPON, POINTS, IMAGE_TEXT
}
java
/**
* 用户类
* 关注公众号【奔跑的码畜】,一起进步不迷路
*
* @author 第七人格
* @date 2023/12/25
*/
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
2、编写福利类,并提供不同福利的发送方法
java
/**
* 根据需求一把梭
* 关注公众号【奔跑的码畜】,一起进步不迷路
*
* @author 第七人格
* @date 2023/12/25
*/
public class Welfare {
// 发放福利的方法
public void sendWelfare(User user, Type type) {
switch (type) {
case COUPON:
sendCoupon(user);
break;
case POINTS:
sendPoints(user);
break;
case IMAGE_TEXT:
sendImageText(user);
break;
default:
throw new IllegalArgumentException("Invalid welfare type");
}
}
// 发放券的方法
private void sendCoupon(User user) {
// 在这里实现发放券的逻辑
System.out.println("Sending coupon to " + user.getName());
}
// 发放积分的方法
private void sendPoints(User user) {
// 在这里实现发放积分的逻辑
System.out.println("Sending points to " + user.getName());
}
// 发放图文的方法
private void sendImageText(User user) {
// 在这里实现发放图文的逻辑
System.out.println("Sending image text to " + user.getName());
}
}
3、编写测试类
java
/**
* 测试策略模式
* 关注公众号【奔跑的码畜】,一起进步不迷路
*
* @author 第七人格
* @date 2023/12/25
*/
public class StrategyTest {
@Test
public void testDemo01() {
Welfare welfare = new Welfare();
User user = new User("张三");
welfare.sendWelfare(user, Type.COUPON);
welfare.sendWelfare(user, Type.POINTS);
welfare.sendWelfare(user, Type.IMAGE_TEXT);
}
}
4、测试结果
Sending coupon to 张三
Sending points to 张三
Sending image text to 张三
二、使用策略模式优化代码
1、抽象福利策略接口
java
/**
* 策略模式 - 福利策略接口
* 关注公众号【奔跑的码畜】,一起进步不迷路
*
* @author 第七人格
* @date 2023/12/25
*/
public interface WelfareStrategy {
void sendWelfare(User user);
}
2、编写具体实现类
java
/**
* 策略模式 - 发放券策略类
* 关注公众号【奔跑的码畜】,一起进步不迷路
*
* @author 第七人格
* @date 2023/12/25
*/
public class CouponStrategy implements WelfareStrategy {
@Override
public void sendWelfare(User user) {
System.out.println("Sending coupon to " + user.getName());
}
}
java
/**
* 策略模式 - 发放图文策略类
* 关注公众号【奔跑的码畜】,一起进步不迷路
*
* @author 第七人格
* @date 2023/12/25
*/
public class ImageTextStrategy implements WelfareStrategy {
@Override
public void sendWelfare(User user) {
System.out.println("Sending image text to " + user.getName());
}
}
java
/**
* 策略模式 - 发放积分策略类
* 关注公众号【奔跑的码畜】,一起进步不迷路
*
* @author 第七人格
* @date 2023/12/25
*/
public class PointsStrategy implements WelfareStrategy {
@Override
public void sendWelfare(User user) {
System.out.println("Sending points to " + user.getName());
}
}
3、编写福利类
java
/**
* 策略模式 - 福利上下文类
* 关注公众号【奔跑的码畜】,一起进步不迷路
*
* @author 第七人格
* @date 2023/12/25
*/
public class WelfareContext {
private WelfareStrategy strategy;
public void setStrategy(WelfareStrategy strategy) {
this.strategy = strategy;
}
public void sendWelfare(User user) {
strategy.sendWelfare(user);
}
}
4、编写测试方法
java
@Test
public void testDemo02() {
com.run2code.design.behavioral.strategy.demo02.WelfareContext welfareContext = new com.run2code.design.behavioral.strategy.demo02.WelfareContext();
User user = new User("李四");
// 使用发放券策略
welfareContext.setStrategy(new CouponStrategy());
welfareContext.sendWelfare(user);
// 使用发放积分策略
welfareContext.setStrategy(new PointsStrategy());
welfareContext.sendWelfare(user);
// 使用发放图文策略
welfareContext.setStrategy(new ImageTextStrategy());
welfareContext.sendWelfare(user);
}
5、测试结果
Sending coupon to 李四
Sending points to 李四
Sending image text to 李四
三、使用工厂模式优化代码
1、通过工厂类,组织具体的创建策略的逻辑即可
java
/**
* 策略模式 - 福利工厂类
* 关注公众号【奔跑的码畜】,一起进步不迷路
*
* @author 第七人格
* @date 2023/12/25
*/
public class WelfareFactory {
public static WelfareStrategy createWelfare(String type) {
if (type == null) {
return null;
}
if (type.equalsIgnoreCase("COUPON")) {
return new CouponStrategy();
} else if (type.equalsIgnoreCase("POINTS")) {
return new PointsStrategy();
} else if (type.equalsIgnoreCase("IMAGE_TEXT")) {
return new ImageTextStrategy();
}
return null;
}
}
2、编写测试方法
java
@Test
public void testDemo03() {
com.run2code.design.behavioral.strategy.demo03.WelfareContext welfareContext = new com.run2code.design.behavioral.strategy.demo03.WelfareContext();
User user = new User("王五");
// 使用工厂方法创建发放券策略对象
WelfareStrategy couponStrategy = WelfareFactory.createWelfare(Type.COUPON.name());
welfareContext.setStrategy(couponStrategy);
welfareContext.sendWelfare(user);
// 使用工厂方法创建发放积分策略对象
WelfareStrategy pointsStrategy = WelfareFactory.createWelfare(Type.POINTS.name());
welfareContext.setStrategy(pointsStrategy);
welfareContext.sendWelfare(user);
// 使用工厂方法创建发放图文策略对象
WelfareStrategy imageTextStrategy = WelfareFactory.createWelfare(Type.IMAGE_TEXT.name());
welfareContext.setStrategy(imageTextStrategy);
welfareContext.sendWelfare(user);
}
3、测试结果
Sending coupon to 王五
Sending points to 王五
Sending image text to 王五
实现要点
策略模式实现要点如下:
1、定义一个公共接口或抽象类,声明所有支持的方法。例子中为:WelfareStrategy
2、创建一系列实现了该接口或继承了该抽象类的类,这些类就是具体的算法。例子中为:CouponStrategy、ImageTextStrategy、PointsStrategy
3、在客户端代码中使用上下文对象来调用具体算法。上下文对象负责将算法的具体实现委托给相应的具体算法类。例子中为:WelfareContext
总结
策略模式是一种行为设计模式,它定义了一系列算法,并将每个算法封装在一个具有共同接口的独立类中,使得它们可以相互替换。策略模式让算法的变化独立于使用它们的客户端。至于如何创建策略,我们一般可以考虑引入工厂模式等其他设计模式。为了抽象得更合理,还经常搭配模版模式使用,等后面讲到模版模式的时候再细说。