🌈 个人主页:danci_
🔥 系列专栏:《设计模式》
💪🏻 制定明确可量化的目标,并且坚持默默的做事。
探索设计模式的魅力:状态模式揭秘-如何优雅地处理复杂状态转换
状态模式是一种行为设计模式,它允许对象在其内部状态改变时改变它的行为。这个模式使得对象看起来好像修改了它的类。以下是几个状态模式的经典场景:
下面我们来实现✨订单处理系统。
使用一个简单的状态机和状态枚举来实现这个场景。下面是一个基于Java的简单实现示例:
public enum OrderStatus {
PENDING_PAYMENT("待支付"),
PAYMENT_RECEIVED("已支付"),
SHIPPED("已发货"),
COMPLETED("已完成");
private final String displayName;
OrderStatus(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return displayName;
}
// 可以根据需要添加更多方法,比如判断是否可以转换到某个状态等
}
public class Order {
private OrderStatus status;
private String orderId;
public Order(String orderId) {
this.orderId = orderId;
this.status = OrderStatus.PENDING_PAYMENT; // 初始状态为待支付
}
public String getOrderId() {
return orderId;
}
public OrderStatus getStatus() {
return status;
}
// 状态转换方法
public void pay() {
if (status == OrderStatus.PENDING_PAYMENT) {
status = OrderStatus.PAYMENT_RECEIVED;
System.out.println("Order " + orderId + " status changed to: " + status.getDisplayName());
} else {
System.out.println("Cannot pay for order " + orderId + " in its current state.");
}
}
public void ship() {
if (status == OrderStatus.PAYMENT_RECEIVED) {
status = OrderStatus.SHIPPED;
System.out.println("Order " + orderId + " status changed to: " + status.getDisplayName());
} else {
System.out.println("Cannot ship order " + orderId + " in its current state.");
}
}
public void complete() {
if (status == OrderStatus.SHIPPED) {
status = OrderStatus.COMPLETED;
System.out.println("Order " + orderId + " status changed to: " + status.getDisplayName());
} else {
System.out.println("Cannot complete order " + orderId + " in its current state.");
}
}
// 可以根据需要添加更多方法和逻辑
}
public class OrderProcessingDemo {
public static void main(String[] args) {
Order order = new Order("12345");
System.out.println("Current order status: " + order.getStatus().getDisplayName());
order.pay();
System.out.println("Current order status: " + order.getStatus().getDisplayName());
order.ship();
System.out.println("Current order status: " + order.getStatus().getDisplayName());
order.complete();
System.out.println("Current order status: " + order.getStatus().getDisplayName());
// 尝试在非法状态下进行状态转换
order.pay(); // 应该不会成功,因为订单已经完成
}
}
在这个实现中,我们直接在Order类中处理了状态转换的逻辑。每个状态转换方法(pay、ship、complete)都会检查当前状态是否允许进行转换,并相应地更新状态或打印错误消息。虽然这个实现很简单,但它缺乏一些设计模式所提供的灵活性和可扩展性。在实际项目中,你可能会考虑使用状态模式、策略模式或模板方法模式等来实现更复杂的状态管理逻辑。然而,根据题目的要求,这里提供了一个不使用设计模式的简单实现。
上述实现确实存在一些缺点,下面逐一分析:
使用状态模式可以有效地解决上述提到的一些缺点。状态模式允许一个对象在其内部状态改变时改变它的行为,使得对象看起来好像修改了它的类。在状态模式中,我们定义状态和状态之间的转换,将状态转换的逻辑封装在状态对象自身中,而不是将其分散在多个条件语句中。
状态模式(State Pattern)是一种行为设计模式,它允许一个对象在其内部状态改变时改变它的行为。状态模式把与特定状态相关的行为封装到一个个的类中,当对象的状态改变时,它的行为也会随着改变。 |
主要组件:
说明:
使用状态模式来实现上述场景时,首先需要定义状态接口和具体的状态类,然后在上下文类(如Order)中维护一个对当前状态的引用。状态类将封装与特定状态相关的行为,包括状态转换。
下面是一个使用状态模式实现的订单处理系统的示例:
public interface OrderState {
void pay(Order order);
void ship(Order order);
void complete(Order order);
// 可能还需要其他方法,如退款、部分发货等
}
public class CreatedState implements OrderState {
@Override
public void pay(Order order) {
// 处理支付逻辑
System.out.println("Order paid.");
order.setState(new PaidState());
}
@Override
public void ship(Order order) {
System.out.println("Cannot ship order in Created state.");
}
@Override
public void complete(Order order) {
System.out.println("Cannot complete order in Created state.");
}
}
public class PaidState implements OrderState {
@Override
public void pay(Order order) {
System.out.println("Order already paid.");
}
@Override
public void ship(Order order) {
// 处理发货逻辑
System.out.println("Order shipped.");
order.setState(new ShippedState());
}
@Override
public void complete(Order order) {
System.out.println("Cannot complete order before it is shipped.");
}
}
public class ShippedState implements OrderState {
@Override
public void pay(Order order) {
System.out.println("Order already paid and shipped.");
}
@Override
public void ship(Order order) {
System.out.println("Order already shipped.");
}
@Override
public void complete(Order order) {
// 处理完成订单逻辑
System.out.println("Order completed.");
order.setState(new CompletedState());
}
}
public class CompletedState implements OrderState {
@Override
public void pay(Order order) {
System.out.println("Cannot pay for a completed order.");
}
@Override
public void ship(Order order) {
System.out.println("Cannot ship a completed order.");
}
@Override
public void complete(Order order) {
System.out.println("Order already completed.");
}
}
public class Order {
private OrderState state;
public Order() {
this.state = new CreatedState(); // 初始状态
}
public void setState(OrderState state) {
this.state = state;
}
public void pay() {
state.pay(this);
}
public void ship() {
state.ship(this);
}
public void complete() {
state.complete(this);
}
// 可能还有其他与订单相关的方法和属性
}
public class StatePatternDemo {
public static void main(String[] args) {
Order order = new Order();
order.pay(); // 当前状态为CreatedState,调用pay会转移到PaidState
order.ship(); // 当前状态为PaidState,调用ship会转移到ShippedState
order.complete(); // 当前状态为ShippedState,调用complete会转移到CompletedState
order.pay(); // 当前状态为CompletedState,不能再支付
order.ship(); // 当前状态为CompletedState,不能再发货
order.complete(); // 当前状态为CompletedState,订单已完成
}
}
在这个示例中,Order类代表上下文,它有一个state字段来保存当前状态,并且提供了pay、ship和complete等方法来触发状态转换。每个具体的状态类(如CreatedState、PaidState等)都实现了OrderState接口,并定义了在当前状态下这些方法的行为。
注:这只是一个简单的示例,实际应用中可能还需要处理更多的状态和行为,并且状态转换的逻辑可能会更加复杂。此外,为了提高代码的可维护性和可读性,还可以考虑使用枚举类型来定义状态,或者使用状态机框架来管理状态转换。
使用状态模式可以有效地解决 1.3 痛点 中提到的一些缺点。状态模式允许一个对象在其内部状态改变时改变它的行为,使得对象看起来好像修改了它的类。在状态模式中,我们定义状态和状态之间的转换,将状态转换的逻辑封装在状态对象自身中,而不是将其分散在多个条件语句中。
以下是状态模式如何解决上述缺点的原因:
通过使用状态模式可以解决硬编码的状态转换逻辑、缺乏灵活性、状态和行为紧密耦合、可维护性问题以及错误处理不足等缺点。通过将状态和行为封装在单独的状态类中,我们实现了状态与行为的解耦,提高了系统的灵活性、可扩展性和可维护性。
核心思想
状态模式的核心思想:将状态和行为分开。 |
在这种模式下,你可以创建一个表示各种状态的对象(称为状态对象),并让这些对象负责处理在该状态下对象的行为。你的主体对象(通常称为上下文对象)将保存一个对当前状态的引用,并在其状态改变时更新这个引用。
实现状态模式通常需要以下步骤:
状态模式的本质
状态模式的本质:根据状态来分离和选择行为 |
何时使用状态模式
状态模式在软件开发中非常有用,特别是当对象的行为需要根据其内部状态的变化而变化时。以下情况可以考虑使用状态模式:
与其他设计模式的对比: