instanceOf(状态模式)的替代方案

Alternative for instanceOf (State Pattern)

我在使用状态模式时遇到问题,我不知道如何在不使用 instanceOf 的情况下检查 State 是否属于某个实例(因为这被认为是错误的练习)。

TCPConnection 持有一个 TCPState 对象。 假设我想要获得状态为 TCPEstablished 的所有 TCPConnections。我该怎么做?

一种方法是:

public List<TCPConnection> getAllEstablished() {
  List<TCPConnection> list = new ArrayList<TCPConnection>();

  for(TCPConnection tcp : allConnections) {
      if(tcp.getState().instanceOf(TCPEstablished)) {
          list.add(tcp);
      }
  }

  return list;
}

但这使用了 instanceOf,我不想使用它。有没有更好的方法?或者我使用 instanceOf 有效吗?

您可以将状态设为枚举

public enum TCPState{
  ESTABLISHED,
  LISTEN,
  CLOSED;

  ..methods go here

}

由于枚举值是完整的对象,它们可以重写方法来执行状态特定的行为。然后,您可以执行 equals() 甚至 == 检查以检查状态。

for(TCPConnection tcp : allConnections) {
  if(tcp.getState()==TCPState.Established)) {
      list.add(tcp);
  }
}

编辑

以下是如何使每个枚举值具有不同的方法实现。

假设TCPState实现了一个接口或者有一个抽象方法foo()

public enum TCPState{
  ESTABLISHED,
  LISTEN,
  CLOSED;

 public abstract void foo();

}

然后您可以像这样为每个值实现不同的方法:

 public enum TCPState{
  ESTABLISHED{
     @Override
     public void foo(){
         System.out.println("established");
     }
  },
  LISTEN{
     @Override
     public void foo(){
         System.out.println("listening");
     }
  },
  CLOSED{
     @Override
     public void foo(){
         System.out.println("closed");
     }
  }
  ;

 public abstract void foo();

}

或者,您可以在 TCPSTate 中创建基础实现而不是声明它 abstract,然后仅在需要执行不同操作的值中使用覆盖。

是的,使用instanceOf被认为是一种气味。此外,检查状态对象的类型与状态模式本身的想法背道而驰(将依赖于状态的行为封装在子类型中,这样这种检查就变得不必要了)。

不过,从技术上讲,您可以通过向 TCPState 添加另一个操作来摆脱 instanceOf,例如bool isEstablished(),并实施它,使其 returns true 仅在 TCPEstablished.

interface TCPState {
    ...
    boolean isEstablished();
}

class TCPEstablished implements TCPState {
    ...
    boolean isEstablished() {
        return true;
    }
}

class TCPClosed implements TCPState {
    ...
    boolean isEstablished() {
        return false;
    }
}

将操作添加到TCPConnection:

class TCPConnection {
    ...
    boolean isEstablished() {
        return this.getState().isEstablished();
    }
}

那么您的操作 getAllEstablished 将如下所示:

List<TCPConnection> getAllEstablished() {
    List<TCPConnection> list = new ArrayList<TCPConnection>();

    for(TCPConnection tcp : allConnections) {
        if(tcp.isEstablished()) {
            list.add(tcp);
        }
    }

    return list;
}

instanceOf 不见了。但是值得吗?