JavaScript中的状态模式

状态模式是一种设计模式,用于在不同状态下改变对象的行为。文中通过电梯和订单状态的例子展示了如何在JavaScript中实现状态模式。电梯类包含各种状态和状态转换方法,而订单类根据用户行为在待支付、已支付、已发货和已取消状态间流转。状态模式的核心是状态的抽象和封装,支持开放-封闭原则,便于扩展新的状态。
摘要由CSDN通过智能技术生成

状态模式是一种非常常用的设计模式,在JavaScript中也有广泛应用。它的作用是通过将对象的行为与状态分离,使得在不同状态下对象的行为可以发生改变。

以下是一个简单的例子,通过状态模式实现一个电梯的状态转换。

首先,我们定义一个电梯类,其中包含电梯的各种状态和状态转换的方法。

```javascript
class Elevator {
  constructor() {
    this.state = new CloseState(this);
  }

  open() {
    this.state.open();
  }

  close() {
    this.state.close();
  }

  run() {
    this.state.run();
  }

  stop() {
    this.state.stop();
  }

  setState(state) {
    this.state = state;
  }
}
```

接下来,我们定义电梯的各个状态类,它们分别对应电梯的打开、关闭、运行和停止状态。

```javascript
class OpenState {
  constructor(elevator) {
    this.elevator = elevator;
  }

  open() {
    console.log('电梯门已经打开');
  }

  close() {
    console.log('关闭电梯门');
    this.elevator.setState(new CloseState(this.elevator));
  }

  run() {
    console.log('电梯门还没关,不能运行');
  }

  stop() {
    console.log('电梯门还没关,不能停止');
  }
}

class CloseState {
  constructor(elevator) {
    this.elevator = elevator;
  }

  open() {
    console.log('打开电梯门');
    this.elevator.setState(new OpenState(this.elevator));
  }

  close() {
    console.log('电梯门已经关闭');
  }

  run() {
    console.log('开始运行');
    this.elevator.setState(new RunState(this.elevator));
  }

  stop() {
    console.log('电梯已经停止');
    this.elevator.setState(new StopState(this.elevator));
  }
}

class RunState {
  constructor(elevator) {
    this.elevator = elevator;
  }

  open() {
    console.log('电梯正在运行,不能打开门');
  }

  close() {
    console.log('电梯正在运行,不能关闭门');
  }

  run() {
    console.log('电梯正在运行');
  }

  stop() {
    console.log('电梯已经停止');
    this.elevator.setState(new StopState(this.elevator));
  }
}

class StopState {
  constructor(elevator) {
    this.elevator = elevator;
  }

  open() {
    console.log('打开电梯门');
    this.elevator.setState(new OpenState(this.elevator));
  }

  close() {
    console.log('电梯门已经关闭');
    this.elevator.setState(new CloseState(this.elevator));
  }

  run() {
    console.log('开始运行');
    this.elevator.setState(new RunState(this.elevator));
  }

  stop() {
    console.log('电梯已经停止');
  }
}
```

最后,我们可以通过以下代码使用电梯类。

```javascript
const elevator = new Elevator();

elevator.run(); // 输出:电梯门还没关,不能

接下来我们可以看一个例子,通过状态模式来实现一个订单状态的流转过程。假设订单可以有三种状态:待支付、已支付、已发货。订单的状态可以根据用户的行为来流转,比如用户支付了订单,订单就从待支付状态变成已支付状态;如果商家发货了,订单就从已支付状态变成已发货状态。

首先我们定义订单状态的接口:

```javascript
class OrderState {
  constructor(order) {
    this.order = order;
  }

  getName() {}

  cancel() {}

  ship() {}
}
```

这个接口定义了三个方法,分别是 `getName`、`cancel`、`ship`。这些方法在不同的状态下可能会有不同的实现。接下来我们定义具体的状态类。

```javascript
class WaitingForPaymentState extends OrderState {
  constructor(order) {
    super(order);
  }

  getName() {
    return 'waitingForPayment';
  }

  cancel() {
    console.log('Cancelling order...');
    this.order.setState(new CancelledState(this.order));
  }

  ship() {
    console.log('Cannot ship order when payment is not received.');
  }
}

class PaidState extends OrderState {
  constructor(order) {
    super(order);
  }

  getName() {
    return 'paid';
  }

  cancel() {
    console.log('Cancelling order...');
    this.order.setState(new CancelledState(this.order));
  }

  ship() {
    console.log('Shipping order...');
    this.order.setState(new ShippedState(this.order));
  }
}

class ShippedState extends OrderState {
  constructor(order) {
    super(order);
  }

  getName() {
    return 'shipped';
  }

  cancel() {
    console.log('Cannot cancel shipped order.');
  }

  ship() {
    console.log('Cannot ship order again.');
  }
}

class CancelledState extends OrderState {
  constructor(order) {
    super(order);
  }

  getName() {
    return 'cancelled';
  }

  cancel() {
    console.log('Cannot cancel cancelled order.');
  }

  ship() {
    console.log('Cannot ship cancelled order.');
  }
}
```

这里定义了四个具体的状态类,分别是待支付状态、已支付状态、已发货状态和已取消状态。每个具体状态类都实现了 `getName`、`cancel`、`ship` 方法,根据状态的不同有不同的实现。

最后我们定义订单类:

```javascript
class Order {
  constructor() {
    this.state = new WaitingForPaymentState(this);
  }

  setState(state) {
    this.state = state;
  }

  cancel() {
    this.state.cancel();
  }

  ship() {
    this.state.ship();
  }
}
```

这个类持有当前订单的状态对象,提供了两个方法 `cancel` 和 `ship`,通过调用状态对象的对应方法实现状态的流转。

使用:

```javascript
const order = new Order();

console.log(`Order is in ${order.state.getName()} state.`); // Order is in waitingForPayment state.

order.cancel(); // Cancelling order...
console.log(`Order is in ${order.state.getName()} state.`); // Order is in cancelled state.

order.ship(); // Cannot ship cancelled order.


```

在状态模式中,我们通常使用一个Context(上下文)对象来控制状态的转换,这个Context对象包含一个State对象,用于表示当前的状态,并且包含了一些可以触发状态转换的方法。当我们调用这些方法时,Context对象会根据当前的状态来执行相应的操作,并且根据一定的规则将状态转换成其他状态。

状态模式的核心是状态的抽象和封装,通过将状态的具体实现封装在State对象中,我们可以使Context对象变得简单和易于维护。另外,状态模式也很好地支持了开放-封闭原则,当我们需要新增一种状态时,只需要添加一个新的State子类即可,不需要修改Context类的代码。

下面是一个简单的状态模式的示例,假设我们正在编写一个交通信号灯程序,可以在红、绿、黄三种状态之间进行切换:

```javascript
// 定义一个状态接口
class State {
  constructor(context) {
    this.context = context;
  }

  // 定义在该状态下执行的方法
  handle() {}
}

// 红灯状态
class RedState extends State {
  constructor(context) {
    super(context);
  }

  handle() {
    console.log("红灯停");
    // 状态转换为绿灯状态
    this.context.setState(new GreenState(this.context));
  }
}

// 绿灯状态
class GreenState extends State {
  constructor(context) {
    super(context);
  }

  handle() {
    console.log("绿灯行");
    // 状态转换为黄灯状态
    this.context.setState(new YellowState(this.context));
  }
}

// 黄灯状态
class YellowState extends State {
  constructor(context) {
    super(context);
  }

  handle() {
    console.log("黄灯等");
    // 状态转换为红灯状态
    this.context.setState(new RedState(this.context));
  }
}

// 定义一个Context类来管理状态
class TrafficLight {
  constructor() {
    // 初始状态为红灯状态
    this.state = new RedState(this);
  }

  // 执行当前状态的方法
  handle() {
    this.state.handle();
  }

  // 设置新的状态
  setState(state) {
    this.state = state;
  }
}

// 使用示例
const trafficLight = new TrafficLight();
trafficLight.handle(); // 红灯停
trafficLight.handle(); // 绿灯行
trafficLight.handle(); // 黄灯等
trafficLight.handle(); // 红灯停
```

在上面的示例中,我们使用State接口来表示状态,并在每个具体的状态类中实现了handle()方法,用于表示在该状态下执行的操作。Context类中包含了当前的状态和执行状态转换的方法setState(),当我们调用handle()方法时,会根据当前的状态来执行相应的操作,并根据一定的规则将状态转换成其他状态。

在状态模式中,状态对象通常是通过工厂方法创建的,以确保每个状态对象都是唯一的。此外,在状态模式中,将状态对象作为参数传递给上下文对象,以确保上下文对象只是在其内部状态改变时发生行为。这种设计模式的主要优点是它在任何时候都允许向对象状态的转换,减少了具体类之间的耦合,并有助于减少 if/else 语句的使用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值