我在使用状态模式时遇到问题,我不知道如何在不使用State
的情况下检查instanceOf
是否属于某个实例(因为这被认为是一个不好的做法)。
TCPConnection
拥有TCPState
个对象。
我们想说我希望得到状态为TCPConnections
的所有TCPEstablished
。我该怎么做?
一种方式是:
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
有效吗?
答案 0 :(得分:4)
是的,使用instanceOf
被认为是一种气味。此外,检查状态对象的类型与状态模式本身的想法相反(在子类型中封装与状态相关的行为,使得这种检查变得不必要)。
尽管如此,您可以通过向instanceOf
添加其他操作来从技术上删除TCPState
,例如bool isEstablished()
,并执行它,使其仅在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
消失了。但它值得吗?
答案 1 :(得分:2)
您可以将状态设为枚举
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
,然后仅在需要执行不同操作的值中使用覆盖。