1

我一直在使用 C++ 做一个小项目(尽管这个问题可能被认为与语言无关)并且我正在尝试编写我的程序,以便它尽可能高效和封装。我是一名自学成才且缺乏经验的程序员,但在使用接口和 OOP 实践时,我正在尝试教自己养成良好的习惯。在访问充当另一个类的子系统的对象的方法时,我主要对典型的“最佳”实践感兴趣。

首先,让我解释一下我的意思:

一个实例ClassGame想要ClassRenderer使用ClassEngine. ClassGame只能访问 的接口ClassEngine,并且ClassRenderer应该是 ClassEngine 的子系统(在抽象层之后)。

我的问题是基于 ClassGame 对象可以间接利用 ClassRenderer 的功能,同时仍然保持快速并在抽象层后面的方式。从我在课程和其他人的代码示例中看到的内容来看,似乎有两种基本方法:

  1. 我通过一系列关于 OOP 设计的在线讲座学到的第一种方法是让一个类在内部将任务委托给它的私有成员对象。[在这个例子中,ClassGame 会调用一个属于 ClassEngine 的方法,而 ClassEngine 会通过调用其中一个方法“秘密地”将该请求传递给它的 ClassRenderer 子系统。] 一种函数调用的“菊花链”。这对我来说很有意义,但似乎它可能比一些替代选项慢。

  2. 我在其他人的代码中看到的另一种方法是使用访问器方法,该方法返回指向特定子系统位置的引用或指针。[因此,ClassGame 将调用 ClassEngine 中的一个简单方法,该方法将返回一个指向构成其 ClassRenderer 子系统的对象的引用/指针]。这条路线对我来说似乎很方便,但它似乎也消除了让私有成员充当更大类的子组件的意义。当然,这也意味着编写更少的“无意识”函数来简单地传递特定任务,因为您可以简单地为每个独立的子系统编写一个 getter 函数。

考虑到面向对象设计的各个重要方面(抽象、封装、模块化、可用性、可扩展性等),同时还要考虑速度和性能,将任务委托给子组件是使用第一种方法还是第二种方法更好?

4

2 回答 2

3

Design Patterns Explained一书在其关于桥接模式的章节中讨论了一个非常相似的问题。显然这一章可以在线免费获得

我建议你阅读它:)

我认为您的 type-1 方法最类似于 OOP 桥接模式。

类型 2,将句柄返回到内部数据是通常应该避免的事情。

于 2012-12-15T12:31:26.237 回答
1

有很多方法可以做你想做的事,这真的取决于上下文(例如,项目有多大,你希望在其他项目中重用多少等)

你有三个类:游戏、引擎和渲染器。您的两个解决方案都使游戏提交到引擎的界面。第二种解决方案还使游戏提交到渲染器的界面。显然,您使用的接口越多,如果接口发生变化,您就越需要更改。

第三个选项怎么样:游戏知道它在渲染方面需要什么,因此您可以创建一个描述这些要求的抽象类。那将是游戏提交的唯一界面。我们称这个接口为 AbstractGameRenderer。

要将其与系统的其余部分联系起来,还有很多方法。一种选择是: 1. 使用现有的 Renderer 类实现这个抽象接口。所以我们有一个使用 Renderer 并实现 AbstractGameRenderer 接口的 GameRenderer 类。2. 引擎创建 Game 对象和 GameRenderer 对象。3. 引擎将 GameRenderer 对象传递给 Game 对象(使用指向 AbstractGameRenderer 的指针)。

结果:游戏可以使用渲染器来做它想做的事。它不知道它来自哪里,它是如何渲染的,谁拥有它——什么都没有。GameRenderer 是一个特定的实现,但其他实现(使用其他渲染器)可以稍后编写。引擎“无所不知”(但这可能是可以接受的)。

稍后,您想将您的游戏逻辑用作另一个游戏中的迷你游戏。您需要做的就是创建适当的 GameRenderer(实现 AbstractGameRenderer)并将其传递给 Game 对象。Game 对象并不关心它是不同的游戏、不同的引擎和不同的渲染器——它甚至不知道。

关键是设计问题有很多解决方案。此建议可能不合适或不可接受,或者可能正是您所需要的。我尝试遵循的原则是: 1. 尽量不要提交您无法控制的界面(如果它们发生变化,您将不得不更改) 2. 现在尝试防止以后会出现的痛苦

在我的示例中,假设如果 Renderer 发生更改,则更改 GameRenderer 比更改诸如 Game 之类的大型组件更容易。但最好坚持原则(并尽量减少痛苦)而不是盲目地遵循模式。

于 2012-12-15T13:20:22.280 回答