文章目录
- 问题描述
- 解决思路
- 具体实现示例
-
- [1. 策略模式](#1. 策略模式)
- [2. 工厂+策略(结合 Map)](#2. 工厂+策略(结合 Map))
- [3. 使用枚举 + 函数式接口](#3. 使用枚举 + 函数式接口)
- [4. 责任链模式](#4. 责任链模式)
- [5. 状态模式](#5. 状态模式)
- 总结
问题描述
经常遇到,根据某个条件执行不同逻辑的需求。
例如:
java
public void handle(String type) {
if (type.equals("A")) {
// 逻辑 A
} else if (type.equals("B")) {
// 逻辑 B
} else if (type.equals("C")) {
// 逻辑 C
} else {
// 默认逻辑
}
}
当条件数量增加时,这段代码会变长、不易维护、不符合开闭原则(增加新的条件需修改原有代码)。
解决思路
常见的方法是将判断逻辑转换为对象的多态行为,或者用查找表(Map)代替条件分支。
主要有以下几种模式:
-
策略模式(Strategy Pattern)
-
工厂模式 + 策略模式
-
状态模式(State Pattern)(适用于状态流转场景)
-
责任链模式(Chain of Responsibility Pattern)
-
使用 Map 消除分支(结合枚举、函数式接口)
具体实现示例
假设有一个订单处理系统,不同类型的订单(普通、VIP、预售)需要不同的折扣计算方式。
1. 策略模式
定义一个策略接口:
java
public interface DiscountStrategy {
double calculate(double price);
}
具体策略:
java
public class NormalDiscount implements DiscountStrategy {
public double calculate(double price) {
return price * 0.9; // 9折
}
}
public class VipDiscount implements DiscountStrategy {
public double calculate(double price) {
return price * 0.8; // 8折
}
}
public class PreSaleDiscount implements DiscountStrategy {
public double calculate(double price) {
return price * 0.85; // 85折
}
}
上下文(Context)使用策略:
java
public class OrderService {
private DiscountStrategy strategy;
public void setStrategy(DiscountStrategy strategy) {
this.strategy = strategy;
}
public double applyDiscount(double price) {
return strategy.calculate(price);
}
}
客户端使用时决定用哪种策略:
java
OrderService service = new OrderService();
service.setStrategy(new VipDiscount());
double result = service.applyDiscount(100);
2. 工厂+策略(结合 Map)
引入一个策略工厂,负责根据类型返回策略实例,消灭调用方的分支:
java
public class DiscountStrategyFactory {
private static Map<String, DiscountStrategy> strategies = new HashMap<>();
static {
strategies.put("NORMAL", new NormalDiscount());
strategies.put("VIP", new VipDiscount());
strategies.put("PRE_SALE", new PreSaleDiscount());
}
public static DiscountStrategy getStrategy(String type) {
DiscountStrategy strategy = strategies.get(type);
if (strategy == null) {
throw new IllegalArgumentException("未知类型");
}
return strategy;
}
}
调用方只需:
java
DiscountStrategy strategy = DiscountStrategyFactory.getStrategy("VIP");
double result = strategy.calculate(100);
这样原来的一长串 if-else 就变成了一个 Map 查找,扩展时只需在 static 块增加一条映射。
3. 使用枚举 + 函数式接口
使用枚举来持有策略:
java
public enum OrderType {
NORMAL(price -> price * 0.9),
VIP(price -> price * 0.8),
PRE_SALE(price -> price * 0.85);
private final DiscountStrategy strategy;
OrderType(DiscountStrategy strategy) {
this.strategy = strategy;
}
public double applyDiscount(double price) {
return strategy.calculate(price);
}
}
其中 DiscountStrategy 可以是一个函数式接口:
java
@FunctionalInterface
public interface DiscountStrategy {
double calculate(double price);
}
使用:
java
double price = 100;
OrderType type = OrderType.VIP;
double result = type.applyDiscount(price);
4. 责任链模式
当流程是顺序判断,并且每个处理器可以选择自己处理或交给下一个,可以用责任链模式。
例如:假设公司采购审批规则如下:
-
采购金额 ≤ 1000元:组长审批即可
-
1000元 < 金额 ≤ 5000元:需要经理审批
-
5000元 < 金额 ≤ 20000元:需要总监审批
-
金额 > 20000元:需要总经理审批
- 定义审批请求类
java
// 采购请求
public class PurchaseRequest {
private double amount; // 采购金额
private String purpose; // 采购目的
private int id; // 请求编号
public PurchaseRequest(double amount, String purpose, int id) {
this.amount = amount;
this.purpose = purpose;
this.id = id;
}
public double getAmount() { return amount; }
public String getPurpose() { return purpose; }
public int getId() { return id; }
}
- 定义审批人抽象类
java
public abstract class Approver {
protected Approver nextApprover; // 下一个审批人
protected String name; // 审批人姓名
protected String position; // 职位
public Approver(String name, String position) {
this.name = name;
this.position = position;
}
// 设置下一个审批人
public void setNextApprover(Approver nextApprover) {
this.nextApprover = nextApprover;
}
// 审批请求的抽象方法
public abstract void processRequest(PurchaseRequest request);
// 转发给下一个审批人
protected void forwardToNext(PurchaseRequest request) {
if (nextApprover != null) {
System.out.println("【" + position + " " + name + "】无权审批,已转交给下一级");
nextApprover.processRequest(request);
} else {
System.out.println("【审批失败】没有合适的审批人处理该请求");
}
}
}
- 实现具体审批人
java
// 组长审批
public class TeamLeader extends Approver {
public TeamLeader(String name) {
super(name, "组长");
}
@Override
public void processRequest(PurchaseRequest request) {
if (request.getAmount() <= 1000) {
System.out.println("【组长 " + name + "】审批通过:采购单 #" + request.getId() +
",金额:" + request.getAmount() + "元,用途:" + request.getPurpose());
} else {
forwardToNext(request);
}
}
}
// 经理审批
public class Manager extends Approver {
public Manager(String name) {
super(name, "经理");
}
@Override
public void processRequest(PurchaseRequest request) {
if (request.getAmount() <= 5000) {
System.out.println("【经理 " + name + "】审批通过:采购单 #" + request.getId() +
",金额:" + request.getAmount() + "元,用途:" + request.getPurpose());
} else {
forwardToNext(request);
}
}
}
// 总监审批
public class Director extends Approver {
public Director(String name) {
super(name, "总监");
}
@Override
public void processRequest(PurchaseRequest request) {
if (request.getAmount() <= 20000) {
System.out.println("【总监 " + name + "】审批通过:采购单 #" + request.getId() +
",金额:" + request.getAmount() + "元,用途:" + request.getPurpose());
} else {
forwardToNext(request);
}
}
}
// 总经理审批
public class GeneralManager extends Approver {
public GeneralManager(String name) {
super(name, "总经理");
}
@Override
public void processRequest(PurchaseRequest request) {
if (request.getAmount() <= 100000) {
System.out.println("【总经理 " + name + "】审批通过:采购单 #" + request.getId() +
",金额:" + request.getAmount() + "元,用途:" + request.getPurpose());
} else {
System.out.println("【审批拒绝】采购金额 " + request.getAmount() +
"元超出总经理权限,需董事会审批");
}
}
}
- 使用
java
public class Client {
public static void main(String[] args) {
// 创建审批人
TeamLeader teamLeader = new TeamLeader("张三");
Manager manager = new Manager("李四");
Director director = new Director("王五");
GeneralManager generalManager = new GeneralManager("赵六");
// 构建责任链
teamLeader.setNextApprover(manager);
manager.setNextApprover(director);
director.setNextApprover(generalManager);
// 创建采购请求
PurchaseRequest request1 = new PurchaseRequest(800, "办公用品", 1001);
PurchaseRequest request2 = new PurchaseRequest(3000, "电脑设备", 1002);
PurchaseRequest request3 = new PurchaseRequest(15000, "服务器", 1003);
PurchaseRequest request4 = new PurchaseRequest(50000, "装修工程", 1004);
// 从链首开始处理
System.out.println("=== 处理采购单 1001 ===");
teamLeader.processRequest(request1);
System.out.println("\n=== 处理采购单 1002 ===");
teamLeader.processRequest(request2);
System.out.println("\n=== 处理采购单 1003 ===");
teamLeader.processRequest(request3);
System.out.println("\n=== 处理采购单 1004 ===");
teamLeader.processRequest(request4);
}
}
5. 状态模式
如果对象在不同状态下行为不同,而且状态会切换,则使用状态模式。
例如订单有「待付款」「已付款」「已发货」「已完成」等状态,每种状态下的操作行为不同。待付款 → 已付款 → 已发货 → 已完成
- 定义订单上下文
java
// 订单类(上下文)
public class Order {
private OrderState currentState; // 当前状态
private int orderId;
private double amount;
public Order(int orderId, double amount) {
this.orderId = orderId;
this.amount = amount;
// 初始状态为待付款
this.currentState = new PendingPaymentState();
System.out.println("创建订单 #" + orderId + ",金额:" + amount + "元,当前状态:待付款");
}
public void setState(OrderState state) {
this.currentState = state;
}
public int getOrderId() { return orderId; }
public double getAmount() { return amount; }
// 状态相关的方法委托给当前状态对象处理
public void pay() {
currentState.pay(this);
}
public void ship() {
currentState.ship(this);
}
public void confirmReceipt() {
currentState.confirmReceipt(this);
}
public void cancel() {
currentState.cancel(this);
}
}
- 定义状态接口
java
public interface OrderState {
// 支付
void pay(Order order);
// 发货
void ship(Order order);
// 确认收货
void confirmReceipt(Order order);
// 取消订单
void cancel(Order order);
// 获取状态名称
String getStateName();
}
- 实现具体状态类
java
// 待付款状态
public class PendingPaymentState implements OrderState {
@Override
public void pay(Order order) {
System.out.println("订单 #" + order.getOrderId() + " 支付成功,金额:" + order.getAmount() + "元");
// 状态流转:待付款 → 已付款
order.setState(new PaidState());
System.out.println("订单状态变更为:已付款");
}
@Override
public void ship(Order order) {
System.out.println("订单 #" + order.getOrderId() + " 尚未付款,不能发货");
}
@Override
public void confirmReceipt(Order order) {
System.out.println("订单 #" + order.getOrderId() + " 尚未付款,不能确认收货");
}
@Override
public void cancel(Order order) {
System.out.println("订单 #" + order.getOrderId() + " 取消成功");
order.setState(new CancelledState());
System.out.println("订单状态变更为:已取消");
}
@Override
public String getStateName() {
return "待付款";
}
}
// 已付款状态
public class PaidState implements OrderState {
@Override
public void pay(Order order) {
System.out.println("订单 #" + order.getOrderId() + " 已付款,请勿重复支付");
}
@Override
public void ship(Order order) {
System.out.println("订单 #" + order.getOrderId() + " 发货成功");
// 状态流转:已付款 → 已发货
order.setState(new ShippedState());
System.out.println("订单状态变更为:已发货");
}
@Override
public void confirmReceipt(Order order) {
System.out.println("订单 #" + order.getOrderId() + " 尚未发货,不能确认收货");
}
@Override
public void cancel(Order order) {
System.out.println("订单 #" + order.getOrderId() + " 申请退款成功,订单取消");
order.setState(new CancelledState());
System.out.println("订单状态变更为:已取消");
}
@Override
public String getStateName() {
return "已付款";
}
}
// 已发货状态
public class ShippedState implements OrderState {
@Override
public void pay(Order order) {
System.out.println("订单 #" + order.getOrderId() + " 已发货,无需支付");
}
@Override
public void ship(Order order) {
System.out.println("订单 #" + order.getOrderId() + " 已发货,请勿重复发货");
}
@Override
public void confirmReceipt(Order order) {
System.out.println("订单 #" + order.getOrderId() + " 确认收货成功");
// 状态流转:已发货 → 已完成
order.setState(new CompletedState());
System.out.println("订单状态变更为:已完成");
}
@Override
public void cancel(Order order) {
System.out.println("订单 #" + order.getOrderId() + " 已发货,不能取消,如需退货请申请售后");
}
@Override
public String getStateName() {
return "已发货";
}
}
// 已完成状态
public class CompletedState implements OrderState {
@Override
public void pay(Order order) {
System.out.println("订单 #" + order.getOrderId() + " 已完成,无需支付");
}
@Override
public void ship(Order order) {
System.out.println("订单 #" + order.getOrderId() + " 已完成,不能发货");
}
@Override
public void confirmReceipt(Order order) {
System.out.println("订单 #" + order.getOrderId() + " 已完成,请勿重复确认收货");
}
@Override
public void cancel(Order order) {
System.out.println("订单 #" + order.getOrderId() + " 已完成,不能取消");
}
@Override
public String getStateName() {
return "已完成";
}
}
// 已取消状态
public class CancelledState implements OrderState {
@Override
public void pay(Order order) {
System.out.println("订单 #" + order.getOrderId() + " 已取消,不能支付");
}
@Override
public void ship(Order order) {
System.out.println("订单 #" + order.getOrderId() + " 已取消,不能发货");
}
@Override
public void confirmReceipt(Order order) {
System.out.println("订单 #" + order.getOrderId() + " 已取消,不能确认收货");
}
@Override
public void cancel(Order order) {
System.out.println("订单 #" + order.getOrderId() + " 已取消,请勿重复取消");
}
@Override
public String getStateName() {
return "已取消";
}
}
- 测试
java
public class OrderTest {
public static void main(String[] args) {
// 创建新订单
Order order = new Order(10001, 299.9);
System.out.println("\n=== 测试支付 ===");
order.pay(); // 待付款 → 支付
System.out.println("\n=== 测试重复支付 ===");
order.pay(); // 已付款状态,不能重复支付
System.out.println("\n=== 测试发货 ===");
order.ship(); // 已付款 → 发货
System.out.println("\n=== 测试确认收货 ===");
order.confirmReceipt(); // 已发货 → 已完成
System.out.println("\n=== 测试取消已完成订单 ===");
order.cancel(); // 已完成,不能取消
System.out.println("\n=== 创建另一个订单测试取消流程 ===");
Order order2 = new Order(10002, 599.9);
order2.pay(); // 支付
order2.cancel(); // 已付款状态可以取消
}
}
本质是把状态对应的行为封装到不同的状态类中,用组合代替分支。
总结
- 策略模式、工厂模式、枚举类 :都属于将可能的情况都列出来,然后根据不同的情况执行不同的方法 。
- 责任链模型 :适用于有顺序要求的情况,能够定义下一个处理对象。
- 状态模式:也是对顺序有一定要求,每个状态都对其他状态设置了处理方法。
github代码地址:https://github.com/TimberWill/design-patterns
以上为个人学习分享,如有问题,欢迎指出:)