维护当前选定的对象是否很好地使用状态模式?
Is it a good use of state pattern to maintain currently selected object?
状态模式的一个典型场景涉及大多数不同的状态,如 closed_connection_state
或 open_connection_state
。就我而言,所有状态基本相同,但操作需要应用于当前选定的对象。
通常这样的事情是使用指向当前选定对象的索引变量完成的,但是使用状态模式是更好的实现方式,如下面的示例所示?
class Object
{
std::string _name;
public:
Object(std::string name) : _name(name)
{
}
void Perform()
{
std::cout << _name << " Perform called\r\n";
}
};
class CurrentObject
{
Object* _a;
Object* _b;
Object* _current;
public:
CurrentObject(Object* a, Object* b) : _a(a), _b(b)
{
_current = a;
}
void Perform()
{
_current->Perform();
// Update _current logic goes here, lets just switch
// the state whenever `Perform` is called.
if (_current == _a)
_current = _b;
else
_current = _a;
};
};
int main()
{
Object a("a"); // program can be in a state when `a` is the current object.
Object b("b"); // or b can become the current object as result of an operation on current object
CurrentObject current(&a, &b); // it assigns the defaults
// assume Perform() does its thing but it also needs to change the current selected object.
// In this example, we assumes the current selection object is always swapped.
current.Perform(); // operates on `a`, the default
current.Perform(); // operates on `b` due state changed in above line
current.Perform(); // operates on `a` doe to state changed in above line again
}
这绝对是一件合理的事情,如果你的状态成倍增加(状态机往往如此),这可能会变得有点难以维护,但它实际上是一个非常好的 OO 风格的状态机实现。
您可能希望您的状态 (a & b) 扩展一个通用的抽象状态,这样当所有状态的功能都相同时,您不必在每个对象中都实现它。
为了扩展,您可能还想 "name" 您的状态并将它们放入哈希表中,一旦它扩展(记住,在编程中您有 1 个或多个)添加新状态将不需要代码更改为您的状态机——但我假设您已经有了这样的东西,只是针对问题缩小了范围。
另请注意,要切换状态您不想直接执行(如您的示例),您可能需要一个方法 (setState) 在执行方法 returns 时更改状态,而不是在 perform 方法本身或当它是 运行 时。事实上,您可以执行 return 一个字符串,指示它是下一个所需状态..
根据评论编辑:
我命名您的州的意思是:
class CurrentObject
{
Object* _a;
Object* _b;
Object* _current;
...
您可能有类似的东西(请原谅我的 java-语法,C# 不是我的主要语言,但我知道它在功能上非常相似)
class CurrentObject
{
Hashtable states=new Hashtable();
Object* _current;
public addState(String stateName, Object* state)
{
states.put(stateName, state)
}
public void Perform()
{
String nextState = _current->Perform();
if(nextState != null)
setState(nextState);
}
public void setState(String stateName)
{
_current = states.get(stateName);
}
}
您的调用代码会执行如下操作:
currentObject = new CurrentObject()
currentObject.addState("state a", _a);
currentObject.addState("state b", _b);
currentObject.setState("state a");
currentObject.perform();
...
我忽略了很多初始化和错误检查。
您的状态机目前只有一个事件:"Perform()"。您可能会发现您需要其他事件,这会使事情变得有点复杂(在 java 中,我可能会使用反射或注释来解决该问题,但不确定 C# 将如何处理)。
状态模式的一个典型场景涉及大多数不同的状态,如 closed_connection_state
或 open_connection_state
。就我而言,所有状态基本相同,但操作需要应用于当前选定的对象。
通常这样的事情是使用指向当前选定对象的索引变量完成的,但是使用状态模式是更好的实现方式,如下面的示例所示?
class Object
{
std::string _name;
public:
Object(std::string name) : _name(name)
{
}
void Perform()
{
std::cout << _name << " Perform called\r\n";
}
};
class CurrentObject
{
Object* _a;
Object* _b;
Object* _current;
public:
CurrentObject(Object* a, Object* b) : _a(a), _b(b)
{
_current = a;
}
void Perform()
{
_current->Perform();
// Update _current logic goes here, lets just switch
// the state whenever `Perform` is called.
if (_current == _a)
_current = _b;
else
_current = _a;
};
};
int main()
{
Object a("a"); // program can be in a state when `a` is the current object.
Object b("b"); // or b can become the current object as result of an operation on current object
CurrentObject current(&a, &b); // it assigns the defaults
// assume Perform() does its thing but it also needs to change the current selected object.
// In this example, we assumes the current selection object is always swapped.
current.Perform(); // operates on `a`, the default
current.Perform(); // operates on `b` due state changed in above line
current.Perform(); // operates on `a` doe to state changed in above line again
}
这绝对是一件合理的事情,如果你的状态成倍增加(状态机往往如此),这可能会变得有点难以维护,但它实际上是一个非常好的 OO 风格的状态机实现。
您可能希望您的状态 (a & b) 扩展一个通用的抽象状态,这样当所有状态的功能都相同时,您不必在每个对象中都实现它。
为了扩展,您可能还想 "name" 您的状态并将它们放入哈希表中,一旦它扩展(记住,在编程中您有 1 个或多个)添加新状态将不需要代码更改为您的状态机——但我假设您已经有了这样的东西,只是针对问题缩小了范围。
另请注意,要切换状态您不想直接执行(如您的示例),您可能需要一个方法 (setState) 在执行方法 returns 时更改状态,而不是在 perform 方法本身或当它是 运行 时。事实上,您可以执行 return 一个字符串,指示它是下一个所需状态..
根据评论编辑:
我命名您的州的意思是:
class CurrentObject
{
Object* _a;
Object* _b;
Object* _current;
...
您可能有类似的东西(请原谅我的 java-语法,C# 不是我的主要语言,但我知道它在功能上非常相似)
class CurrentObject
{
Hashtable states=new Hashtable();
Object* _current;
public addState(String stateName, Object* state)
{
states.put(stateName, state)
}
public void Perform()
{
String nextState = _current->Perform();
if(nextState != null)
setState(nextState);
}
public void setState(String stateName)
{
_current = states.get(stateName);
}
}
您的调用代码会执行如下操作:
currentObject = new CurrentObject()
currentObject.addState("state a", _a);
currentObject.addState("state b", _b);
currentObject.setState("state a");
currentObject.perform();
...
我忽略了很多初始化和错误检查。
您的状态机目前只有一个事件:"Perform()"。您可能会发现您需要其他事件,这会使事情变得有点复杂(在 java 中,我可能会使用反射或注释来解决该问题,但不确定 C# 将如何处理)。