我们应该用什么来代替“经理”?良好的 OOP 设计中的类?

发布于 2024-09-29 17:06:48 字数 751 浏览 0 评论 0原文

我在设计游戏引擎时遇到了麻烦。例如:

当我想到资源时,我想到ResourceManager类来管理我的引擎上的资源。

这个类有几个职责

  • 加载资源。
  • 通过标识符映射资源。
  • 确保资源仅加载一次。
  • 释放未使用的资源(使用智能指针)。

这对我有用,但我在每个 OOP 设计教程中都读过,管理器是具有高耦合低内聚模糊类。我理解这一点,我也同意,但我几乎搜索了整个互联网,以找到经理的真正替代方案的明确示例,但我没有找到。

例如,有人解释说,ResourceManager 应该分为更小的类:ResourceFactoryResourceCollectionResourceCache ResourceFacade...

我知道所有这些设计模式(工厂、集合、外观等),但我实际上不明白如何将它们结合起来创建一个(易于管理)资源管理系统。

我的问题是:是否有一些带有清晰示例的教程或文档?有人可以解释一下这个系统的例子吗?如果您能用 C++ 或其他类似语言编写一个小示例,我将非常感谢。

预先感谢您的帮助!

I'm having trouble designing my game engine. For example:

When I think in Resources, I think in a ResourceManager class to manage resources on my engine.

This class gets several responsibilities:

  • Load resources.
  • Map resources by an identifier.
  • Ensure that resources are loaded only once.
  • Free unused resources (using smartpointers).

This works for me, but I have read on every OOP design tutorial that managers are ambiguous classes with high coupling and low cohesion. I understand this, and I agree, but I searched almost the whole Internet to find a clear example of a real alternative to Managers but I didn't found it.

Some people explain, for example that a ResourceManager should be divided into smaller classes: A ResourceFactory, a ResourceCollection, a ResourceCache, a ResourceFacade...

I know all this design patterns (Factory, Collection, Facade, etc.) But I don't actually understand how this can be joined to create a (easy to manage) resource management system.

My question is: Is there some tutorial or document with a clear example? Can someone explain an example of this system? I'll thank you if you can write a small example in C++ or another similar language.

Thanks in advance for your help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

败给现实 2024-10-06 17:06:48

你几乎已经说过了:

这个类承担多项职责

(原来的重点)。

这违反了单一责任原则。此外,“Manager”一词暗示着一个管理其他对象的对象,这与对象应该封装数据和行为的面向对象原则相矛盾。这很快就会导致 Feature Envy 代码气味。

将经理分成许多较小的类别是正确的做法。为了使它们易于管理,您可以在它们之上实现Facade

You almost said it already:

This class gets several responsibilities

(original emphasis).

This violates the Single Responsibility Principle. Additionally, the word Manager suggest an object that manages other objects, which is at odds with the object-oriented principle that objects should encapsulate both data and behavior. This quickly leads to the Feature Envy code smell.

Dividing the manager into many smaller classes is the correct thing to do. To keep them manageable, you can implement a Facade over them.

宛菡 2024-10-06 17:06:48

也许:

  • 加载资源-> ResourceLoader
  • 通过标识符映射资源 -> ResourceMapper
  • 确保资源仅加载一次 -> CachedResourceLoader / 这个在尚未加载时使用 ResourceLoader
  • 释放未使用的资源(使用智能指针) -> ? / 不确定这一点,但加载+卸载似乎是高度凝聚力的概念

有关“释放未使用的资源”的评论中有额外信息:

首先,让我们明确一下,我们只涉及上述内容中的两个: ResourceMapper 和 CachedResourceLoader。由于 ResourceLoader 实例是从 CachedResource 使用的,因此它不会暴露给其余代码。

请注意,以下内容取决于领域知识,因此我将保持开放/您会知道其中哪些有意义/适用于您拥有的部分。我想说这里有 3 个选项:

  • ResourceMapper 使用 CachedResourceLoader,并且您只需将较早的选项暴露给其余代码。
    • 在这种方法中,ResourceMapper 有一个入口点,因此它控制 FreeUnused() 是有意义的。
    • 一旦确定可以释放资源,就会将其从地图中删除。如果需要,它会调用 CachedResourceLoader 的特定项的 Unload
  • 。调用者会使用 CachedResourceLoader 和 ResourceMapper。
    • 如果您只需要从ResourceMapper中释放Unused,那么只需将其添加到那里即可。
    • 如果需要同时将其释放,请选择以下其中之一:
    • .FreeUnused在ResourceMapper中接收一个cachedResourceLoader。从地图中确定/删除项目后,它将要释放的资源列表传递给cachedResourceLoader实例
    • ResourceMapper 中的

    • .FreeUnused 返回从映射中释放的资源列表。调用者在 cachedResourceLoader 上调用 .Unload,将资源列表传递给 Unload。也许您在调用者中有一个不错的位置,这两个调用很适合。
  • 您确实使用了 ResourceManager,但它没有使用其中的所有实现,而是使用 ResourceMapper 和 CachedResourceLoader。它会非常薄,只需要调用其他函数,特别是上面最后一个子项目符号中的 .FreeUnused 和 .Unload 调用。

最后一点:我认为将责任分开并且对此感到强烈是绝对值得的。也就是说,这是我最遵循的 SOLID 原则,我不会记住模式名称,也不会过多关注诸如 Manager 类之类的规则是不好的。

Maybe:

  • Load resources -> ResourceLoader
  • Map resources by an identifier -> ResourceMapper
  • Ensure that resources are loaded only once -> CachedResourceLoader / this one uses the ResourceLoader when it doesn't already have it loaded
  • Free unused resources (using smartpointers) -> ? / not sure about this one, but load+unload seems like highly cohesive concepts

re extra info in the comment about "Free unused resources":

First, let's clear that we only have 2 of the above involved: ResourceMapper and CachedResourceLoader. As the ResourceLoader instance is used from the CachedResource, it's not exposed to the rest of the code.

Note that the following depends on the domain knowledge, so I'll keep it open / you'll know which of these make sense / applies to the pieces you have. I'd say there are 3 options here:

  • ResourceMapper uses CachedResourceLoader, and you only expose the earlier to the rest of the code.
    • In this approach it there is a single entry point through ResourceMapper, so it makes sense it controls FreeUnused().
    • Once it determines it can free a resource, it'll remove it from the map. If needed it'd call an Unload for specific items to the CachedResourceLoader
  • Both CachedResourceLoader and ResourceMapper are used by the caller.
    • If you only need to FreeUnused from the ResourceMapper, then just add it there.
    • If it needs to be freed from both, one of:
    • .FreeUnused in the ResourceMapper receives a cachedResourceLoader. After determining/removing the items from the map, it passes the list of resources to free to the cachedResourceLoader instance
    • .FreeUnused in the ResourceMapper returns the list of resources freed from the map. The caller calls .Unload on the cachedResourceLoader passing the list of resources to Unload. Maybe you have a nice place in the caller these 2 calls would fit well.
  • You do use a ResourceManager, but instead of having all the implementations in there, it uses the ResourceMapper and CachedResourceLoader. It'd be very thin, just doing calls to the others, in particular the .FreeUnused and .Unload calls in the last sub bullet above.

A final note: I think it's definitely worth it to separate the responsibilities and feel strong about doing so. That said, it's the SOLID principles I follow the most, I don't memorize pattern names and don't pay that much attention to rules like Manager classes are bad.

活雷疯 2024-10-06 17:06:48

您不需要对设计模式或特定架构抱有教条。只需做任何有意义的事情并妥善记录

换句话说,因为较大的类具有多重职责而将一个类分解为较小的类是一个很好的原则,但不是一个法律。你不想不惜任何代价去追随它。看看应用它的优点和缺点。有时,将一个类分解为更小的类可以让您更好地控制职责,但代价是这些类之间的大量沟通。在您的示例中,您也可以实现不同的类来进行资源加载、缓存、映射、保存等。但是,如果每个类都需要与其他类通信才能执行其工作,那么分解就不值得做,因为它耦合度高,这是不好的;将所有内容放在一个类中。

有时我认为设计模式给软件开发世界带来的损害和清晰度一样多! :-)

You don't need to be dogmatic about design patterns or a particular architecture. Just do whatever makes sense and document it well.

In other words, decomposing a class into smaller classes because the larger class has multiple responsabilities is a good principle, but not a law. You don't want to follow it at any cost. Look at the pros and cons of applying it. Sometimes, decomposing a class into smaller classes gives you more control over responsaibilities, but at the expense of a great deal of communication among those classes. In your example, you might as well implement different classes for resource loading, caching, mapping, saving, etc. But if each class needs to talk to the others in order to perform its work, then the decomposition is not worth doing, because it entails high coupling, which is bad; keep it all in a single class.

Sometimes I think that design patterns have brought about as much damage as clarity to the software development world! :-)

生寂 2024-10-06 17:06:48

我认为您的解决方案不一定有问题。
恕我直言,如果您从面向方面编程的角度思考您所说的内容,
它只是您的资源的一个方面,将由类处理。

尽管如果你从大的角度思考,你的代码库可能会发展成数百行,所以最好分解你的基础设施功能(领域驱动设计模式)。

我认为您的类是一个有凝聚力的类,并且 manager 名称并不总是一个坏兆头,只是它巩固了许多可能不相关的类的控制流,这些类相互协作以完成任务。

如果您对缓存和映射的要求很容易发生变化,也许最好分离您的关注点。

尝试编写组织良好的代码时的经验法则是一开始不要太认真,继续前进时请注意代码异味,并在必要时重构或重构为模式。

I don't think something is necessarily wrong with your solution.
IMHO if you think about stuff you've said from Aspect Oriented Programming's point of view,
it's just an aspect on your resources that will be handled by a class.

Although if you think in large, your code base may evolved in hundreds of lines, so it would be better to break down your Infrastructure functions(Domain Driven Design Patterns).

I think your class is a cohesive one and the manager name is not always a bad sign except that it consolidates the control flow of many possibly unrelated classes that collaborate with each other to accomplish a task.

If your requirements about caching and mapping is prone to change maybe it would be better to Separate your Concerns.

Rule of thumb when trying to write a well organized code is don't take it too serious at first, watch out code smells as you go forward and refactor or refactor to patterns when necessary.

红焚 2024-10-06 17:06:48

我知道所有这些设计模式(工厂、集合、外观等),但我实际上不明白如何将它们结合起来创建一个(易于管理)资源管理系统。

谁说他们应该结合在一起?然后你又回到了起点,不是吗?分解管理器类的全部要点是您最终会得到多个更简单的组件。如果您需要缓存功能,请与缓存对话。如果您需要资源加载功能,请与资源加载器交谈。

I know all this design patterns (Factory, Collection, Facade, etc.) But I don't actually understand how this can be joined to create a (easy to manage) resource management system.

Who says they should be joined together? Then you're back where you started, aren't you? The entire point in breaking up manager classes is that you end up with multiple simpler components. If you need the caching functionality, you talk to the cache. If you need the resource loading functionality you talk to the resource loader.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文