我正在编写一个iPhone应用程序,我发现当我添加功能时,可以预见,状态的排列会急剧增加。
然后我发现自己必须在表单的位置添加代码:If this and that and not the other then do x and y and set state z
是否有人建议采用系统的方法来解决这个问题?
即使我的应用是iPhone,我认为这适用于许多GUI案例。
答案 0 :(得分:2)
通常,用户界面应用程序始终在等待事件发生。该事件可以是用户的动作(点击,摇动iPhone,在虚拟键盘上键入字母),或者通过另一个过程(网络数据包变得可用,电池耗尽)或时间事件(计时器到期)。每当发生事件时(“如果这样”),您可以查询应用程序的当前状态(“......而不是其他”),然后执行某些操作(“执行x和y”),这很可能会发生变化应用程序状态(“设置状态z”)。这就是您在问题中描述的内容。这是一般模式。
没有一种系统的方法可以做到正确,但是当你提出方法的建议时,这里有一些建议:
提示1:使用尽可能少的实际数据结构和变量来尽可能地表示内部状态,避免一切重复状态(直到遇到性能问题)。这使得“do x和y and set state z”更短,因为状态被隐式设置。简单的例子:而不是(C ++中的例子)
if (namelen < 20) { name.append(c); namelen++; }
使用
if (name.size() < 20) { name.append(c); }
第二个示例正确地避免了复制状态变量'namelen',使得操作部分更短。
提示2:每当复合条件(X和Y或Z)在程序中多次出现时,将其抽象为一个过程,而不是
if ((x && y) || z) { ... }
写
bool my_condition() { return (x && y) || z; }
if (my_condition()) { ... }
提示3:如果您的用户界面具有少量明确定义的状态,并且状态会影响事件的处理方式,则可以将状态表示为从接口继承以处理这些事件的类的单例实例。例如:
class UIState {
public:
virtual void HandleShake() = 0;
}
class MainScreen : public UIState {
public:
void HandleShake() { ... }
}
class HelpScreen : public UIState {
public:
void HandleShake() { ... }
}
实例化每个派生类的一个实例,然后指向一个指向当前状态对象的指针:
UIState *current;
UIState *mainscreen = new MainScreen();
UIState *helpscreen = new HelpScreen();
current = mainscreen;
要处理震动,请致电:
current->HandleShake();
稍后更改UI状态:
current = helpscreen;
通过这种方式,您可以将与状态相关的过程收集到类中,并将它们封装并抽象出来。当然,您可以将各种有趣的东西添加到这些特定于州(单例)的类中。
提示4:通常,如果您有N个布尔状态变量和T个可以触发的不同事件,则在所有可能条件下的所有可能事件的“矩阵”中都有T * 2 ** N个条目。它需要您的架构视图和领域专业知识才能正确识别矩阵中那些最符合逻辑和自然的封装到对象中的维度和区域,以及如何。这就是软件工程的意义所在。但是如果你试图在没有适当的封装和抽象的情况下完成你的项目,你就无法扩展它。