组件模式

本文探讨了在软件设计中,组件模式如何作为继承的替代方案,用于实现解耦和代码重用。当类变得庞大复杂或者需要隔离不同领域时,组件模式显得更为适用。虽然组件模式引入了更多复杂性,如组件间的通信和内存管理,但它提供了更大的灵活性。文章提到了组件间通信的几种方式,并建议根据需求从简单开始,逐步增加复杂性。
摘要由CSDN通过智能技术生成

组件模式

谈一谈继承与组合

当面向对象语言第一次接触这个场景时,继承是它箱子里最闪耀的工具。 它被认为是代码无限重用之锤,编程者常常挥舞着它。 然而我们痛苦地学到,事实上它是一把重锤。 继承有它的用处,但对简单的代码重用来说太过复杂。相反,在今日软件设计的趋势是尽可能使用组件代替继承。 不是让两个类继承同一类来分享代码,而是让它们拥有同一个类的实例。

使用场景

组件通常在定义游戏实体的核心部分中使用,但它们在其他地方也有用。 这个模式应用在在如下情况中:

  • 有一个涉及了多个领域的类,而你想保持这些领域互相隔离。

  • 一个类正在变大而且越来越难以使用。

  • 想要能定义一系列分享不同能力的类,但是使用继承无法让你精确选取要重用的部分。

有得有失

  • 优点:解耦与重用
  • 挑战:

组件模式相较直接在类中编码的方式为类本身引入了更多的复杂性。每个概念上的“对象”成为一系列必须被同时实例化、初始化,并正确关联的对象的集群。不同组件之间的通信变得更具挑战,而且对它们所占用内存的管理将更复杂。

另一个影响是,往往需要通过一系列的间接引用来处理问题,即从容器对象获取到组件,再调用组件的方法。

组件之间传递信息

下面列举的方法不是互斥的:

  1. 通过修改容器对象的状态
    • 优点:组件保持解耦。
    • 缺点:
      • 组件间需要共享的数据都由容器对象来保管。但是通常某些数据只被少部分组件所需要。所有数据都在容器类中,会让它混乱。更糟的是,如果我们为不同组件配置使用相同的容器类,最终会浪费内存存储不被任何对象组件需要的状态。
      • 这让组件的通信基于组件运行的顺序。
  2. 通过它们之间相互引用
    • 优点:简单快捷。
    • 缺点:两个组件紧绑在一起。
  3. 通过发送消息
    • 优点:
      • 同级组件解耦。
      • 容器类很简单。
    • 缺点:
      • 逻辑复杂。
      • 增加了开销。

原作者按:

不出意料的,这里没有最好的答案。这些方法你最终可能都会使用一些。 共享状态对于每个对象都有的数据是很好用的——比如位置和大小。

有些不同领域仍然紧密相关。想想动画和渲染,输入和AI,或物理和粒子。 如果你有这样一对分离的组件,你会发现直接相互引用也许更加容易。

消息对于“不那么重要”的通信很有用。对物理组件发现事物碰撞后发送消息让音乐组件播放声音这种事情来说,发送后不管的特性是很有效的。

就像以前一样,我建议你从简单的开始,然后如果需要的话,加入其他的通信路径。

组件模式(Component Pattern)是一种常用的面向对象设计模式,它将一个大型的对象拆分成多个小型的组件,每个组件都有独立的职责和行为,并可以互相组合以构建出复杂的系统。在C++中,实现组件模式通常需要用到继承、虚函数、抽象类等特性。 以下是一个简单的组件模式示例: ``` // 抽象组件类 class Component { public: virtual void operation() = 0; }; // 具体组件类A class ComponentA : public Component { public: void operation() override { std::cout << "Component A operation" << std::endl; } }; // 具体组件类B class ComponentB : public Component { public: void operation() override { std::cout << "Component B operation" << std::endl; } }; // 抽象容器类 class Container { public: virtual void add(Component* component) = 0; virtual void remove(Component* component) = 0; virtual void operation() = 0; }; // 具体容器类 class Composite : public Container { private: std::vector<Component*> components; public: void add(Component* component) override { components.push_back(component); } void remove(Component* component) override { auto it = std::find(components.begin(), components.end(), component); if (it != components.end()) { components.erase(it); } } void operation() override { for (auto component : components) { component->operation(); } } }; // 示例代码 int main() { ComponentA componentA; ComponentB componentB; Composite composite; composite.add(&componentA); composite.add(&componentB); composite.operation(); return 0; } ``` 在上面的示例代码中,我们先定义了一个抽象组件类`Component`,其中包含一个纯虚函数`operation()`,用于执行组件的操作。然后,我们定义了两个具体组件类`ComponentA`和`ComponentB`,分别实现了`operation()`函数。接着,我们定义了一个抽象容器类`Container`,其中包含三个纯虚函数,分别用于添加组件、删除组件和执行组件的操作。最后,我们定义了一个具体容器类`Composite`,实现了`Container`类中的三个函数,并通过容器的方式管理多个组件。在主函数中,我们创建了一个`ComponentA`对象、一个`ComponentB`对象和一个`Composite`对象,将`ComponentA`和`ComponentB`对象添加到`Composite`对象中,并调用`Composite`对象的`operation()`函数,以执行所有组件的操作。 通过组件模式,我们可以将一个大型的系统拆分成多个小型的组件,每个组件都可以独立地进行开发、测试和维护。同时,组件模式还可以通过组合不同的组件,构建出各种不同的系统,从而提高系统的可复用性和可扩展性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值