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
不见了。但是值得吗?
我在使用状态模式时遇到问题,我不知道如何在不使用 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
不见了。但是值得吗?