我在为游戏设计GUI时遇到问题。到目前为止,我已经得出结论,CompositePattern将允许我对所有UIComponents一视同仁,无论其中一个是UI按钮,另一个是UIMenu。这是UIComponent接口:
class UIComponent {
virtual void Init() = 0;
virtual void Draw() = 0;
}
我的每个实现类(UIFrame、UIButton、UITextBox、UIMenu…)现在都可以相互工作了。此设计中的复合类是UIMenu类,因为它is AUIComponent和HAS AUIComponent。
class UIMenu : public UIComponent {
private:
vector<UIComponent*> children_;
public:
virtual void Init() {
// Initialize any data
};
virtual void Draw() {
// Delegate drawing to each child
for each(UIComponent* component in children_) {
component->Draw();
}
};
void AddComponent(UIComponent* child) {...};
void RemoveComponent(UIComponent* child) {...};
}
因为我想在所有UIComponents中支持drag-n-drop功能,所以每个组件都需要Position、Dimensions、Scale、Parent和Layer(ComponentData)。要做到这一点,我需要将它们分别添加到每个实现类中,对我来说,这似乎是错误的做法
class UIFrame : public UIComponent {
private:
string imgID_;
int layer_;
double relX_, relY_;
double width_, height_;
double scaleX_, scaleY_;
UIComponent* parent_;
public:
virtual void Init() {...}
virtual void Draw() {...}
...
};
这不是已经打破了复合模式吗?因为我现在已经通过聚合将每个组件实现都变成了复合?如果我希望我的UIButton具有相同的定位、转换和缩放能力,我需要从UIFrame继承或将数据成员复制到UIButton中。
有没有更好的方法来创建UIComponent接口的实现?例如,我们可以将UIFrame作为所有需要移动功能的组件的基类,而不是UIButton、UITextBox、UILabel等。现在,像UIButton这样的组件将是UIFrame的子级,以便重用ComponentData。
将涉及定位、转换和缩放的方法放在UIComponent接口中会更好吗?这将强制每个组件都知道如何在屏幕上操作自己。然而,我仍然有一个问题,"我把ComponentData(位置、尺寸、比例)放在哪里?"
我真的很喜欢复合模式的想法,以及原子化处理树结构的叶子和树枝节点的能力。它还允许我使用Decorator Pattern创建UIMenu对象的多次迭代,这样我就可以通过更改每个菜单的UIComponents来拥有InventoryMenu、CharacterInfoMenu、OptionsMenu等。
您可以创建一个超类UIDraggable
,其中包含支持拖放的数据项和方法,每个可拖动元素都可以继承它。UIDraggable
可以继承UIComponent
。