阻止Balking模式

19-04-24 jdon
         

目的

Balking Pattern用于防止对象在不完整或不适当的情况下执行某些代码。

维基百科说

balking模式是一种软件设计模式,仅在对象处于特定状态时才对对象执行操作。例如,如果一个对象读取ZIP文件,而一个调用方法在zip文件未打开时调用该对象的get方法,则该对象将在请求时“停止”。例如,在Java编程语言中,在这些情况下可能会抛出IllegalStateException。

源代码

在这个示例实现中,WashingMachine是一个对象,它有两种状态:启用和清洗。如果机器已启用,则状态将更改为“正在清洗”,任何其他线程都无法调用及执行此操作。另一方面,如果它已经清洗过,则任何其他线程无法再执行wash()操作。

类图

第1步:创建洗衣机类。

package com.iluwatar.balking;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Washing machine class
 */
public class WashingMachine {

  private static final Logger LOGGER = LoggerFactory.getLogger(WashingMachine.class);

  private WashingMachineState washingMachineState;

  public WashingMachine() {
    washingMachineState = WashingMachineState.ENABLED;
  }

  public WashingMachineState getWashingMachineState() {
    return washingMachineState;
  }

  /**
   * Method responsible for washing
   * if the object is in appropriate state
   */
  public void wash() {
    synchronized (this) {
      LOGGER.info("{}: Actual machine state: {}", Thread.currentThread().getName(), getWashingMachineState());
      if (washingMachineState == WashingMachineState.WASHING) {
        LOGGER.error("ERROR: Cannot wash if the machine has been already washing!");
        return;
      }
      washingMachineState = WashingMachineState.WASHING;
    }
    LOGGER.info("{}: Doing the washing", Thread.currentThread().getName());
    try {
      Thread.sleep(50);
    } catch (InterruptedException ie) {
      ie.printStackTrace();
    }
    endOfWashing();
  }

  /**
   * Method responsible of ending the washing
   * by changing machine state
   */
  public synchronized void endOfWashing() {
    washingMachineState = WashingMachineState.ENABLED;
    LOGGER.info("{}: Washing completed.", Thread.currentThread().getId());
  }

}

第2步: 创建WashingMachineState描述机器的状态,它可以启用并准备好在洗涤期间工作。

package com.iluwatar.balking;

public enum WashingMachineState {
  ENABLED, WASHING
}

第3步:让我们测试一下这种设计模式。

public class BalkingPatternDemo {

  private static final Logger LOGGER = LoggerFactory.getLogger(App.class);

  /**
   * @param args the command line arguments - not used
   */
  public static void main(String... args) {
    final WashingMachine washingMachine = new WashingMachine();
    ExecutorService executorService = Executors.newFixedThreadPool(3);
    for (int i = 0; i < 3; i++) {
      executorService.execute(washingMachine::wash);
    }
    executorService.shutdown();
    try {
      executorService.awaitTermination(10, TimeUnit.SECONDS);
    } catch (InterruptedException ie) {
      LOGGER.error("ERROR: Waiting on executor service shutdown!");
    }
  }

}

适用性

使用Balking模式时

  • 您希望仅在对象处于特定状态时才对其调用操作

  • 对象通常只处于一种容易暂时停止的状态,但时间不确定。