在优秀的OOP设计中我们应该使用什么而不是"经理"类?

Dan*_*ani 35 oop design-patterns

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

当我在参考资料中思考时,我认为在ResourceManager类中管理我的引擎上的资源.

这个课有几个职责:

  • 加载资源.
  • 按标识符映射资源.
  • 确保资源仅加载一次.
  • 免费使用未使用的资源(使用智能指针).

这对我有用,但我已经阅读了每个OOP设计教程,管理者是具有高耦合低内聚的模糊类.我理解这一点,并且我同意,但我几乎在整个互联网上搜索了一个明确的例子,说明了管理者真正的替代方案,但我没有找到它.

有些人解释说,例如,ResourceManager应该分成更小的类:ResourceFactory,ResourceCollection,ResourceCache,ResourceFacade ......

我知道所有这些设计模式(工厂,集合,外观等)但我实际上并不了解如何将其加入以创建(易于管理)资源管理系统.

我的问题是:是否有一些教程或文档有明确的例子?有人能解释一下这个系统的例子吗?如果你能用C++或其他类似的语言写一个小例子,我会感谢你的.

在此先感谢您的帮助!

Mar*_*ann 15

你几乎已经说过了:

这门课有几个责任

(原始重点).

这违反了单一责任原则.此外,管理单词提示管理其他对象的对象,这与面向对象的原则不一致,即对象应该封装数据和行为.这很快就会导致Feature Envy代码异味.

将经理划分为许多较小的类是正确的做法.为了使它们易于管理,您可以对它们实施Facade.

  • 我也认为有些人用所有这些"原则"和"成语"如此努力地推动OO,几乎不可能编写任何符合它们的代码.毕竟,其中很少是神圣的文字 - 它们只是不同民族关于如何处理OO的想法,而不是法律. (14认同)
  • 并保持它管理的鸿沟门面成许多较小的外墙每一个责任和包装一个门面在该门面...)对不起,我不能有任何更具建设性的,因为答案是只是一个流行语的集合 (9认同)
  • @John:不,图书馆是一种代表图书馆的方式."Bookmanager"是......管理书籍的东西.我甚至都不知道这意味着什么.一个车库不"管理汽车",它只是存放汽车,而不是在使用,有时收取钱.这正是经理类的问题.*目前尚不清楚它们的含义*.当我遇到"CarManager"课程时,我应该假设它只是你车库的名字吗?或者也许是一些大型控制器类定期更新当前正在驾驶的每辆车的位置?也许它是所有汽车的集中注册表. (7认同)

egl*_*ius 12

也许:

  • 加载资源 - > ResourceLoader
  • 通过标识符映射资源 - > ResourceMapper
  • 确保资源只加载一次 - > CachedResourceLoader/这个使用ResourceLoader它尚未加载的时间
  • 免费使用未使用的资源(使用smartpointers) - >?/不确定这个,但加载+卸载似乎是高度凝聚力的概念

关于"免费未使用资源"的评论中的额外信息:

首先,让我们清楚一点,我们只涉及上面的两个:ResourceMapper和CachedResourceLoader.由于在CachedResource中使用了ResourceLoader实例,因此它不会暴露给其余的代码.

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

  • ResourceMapper使用CachedResourceLoader,您只将前面的代码公开给其他代码.
    • 在这种方法中,通过ResourceMapper只有一个入口点,因此控制FreeUnused()是有意义的.
    • 一旦确定它可以释放资源,它就会将其从地图中删除.如果需要,它会将特定项的Unload调用到CachedResourceLoader
  • 调用者使用CachedResourceLoader和ResourceMapper.
    • 如果您只需要从ResourceMapper中获取FreeUnused,那么只需将其添加到那里即可.
    • 如果它需要从两者中解放出来,其中一个:
    • .FreeUnper在ResourceMapper中接收一个cachedResourceLoader.在确定/从地图中删除项目后,它会将资源列表传递给cachedResourceLoader实例
    • .FreeUnper中的.FreeUnused返回从映射中释放的资源列表.调用者在cachedResourceLoader上调用.Unload,将资源列表传递给Unload.也许你在呼叫者中有一个不错的地方,这两个电话很适合.
  • 您确实使用了ResourceManager,但它没有使用所有实现,而是使用ResourceMapper和CachedResourceLoader.它非常薄,只是对其他人进行调用,特别是上面子项目中的.FreeUnused和.Unload调用.

最后一点:我认为将责任分开并且对这样做感到强烈是绝对值得的.也就是说,这是我最常遵循的SOLID原则,我没有记住模式名称,也没有那么多关注管理类很糟糕的规则.

  • @Dani:删除它.然后使用*real*引用计数智能指针(例如Boost中的那个).一个理智的智能指针实现*自动*删除对象的引用计数达到零(并回答你的下一个问题,你的ResourceMap然后可以保持弱指针,以避免它通过阻止ref计数器达到零保持对象活着) (3认同)
  • @Dani:是的,听起来很对.一般来说,神奇的词是RAII:每个资源的生命周期应该映射到包装类的生命周期.智能指针是这种包装器对象的一个​​示例(当ref参数计数器达到零时,ref-counting会删除它拥有的资源,但存在许多其他类型).通常,这允许您编写C++代码,其中资源只管理自己,并在不再需要时自动删除.当它们超出范围时,或者当它们的参考计数器达到零时. (2认同)

Ces*_*Gon 12

您不需要对设计模式或特定架构进行教条.刚做任何有意义和记录它做好.

换句话说,将一个类分解为更小的类是因为较大的类具有多个响应性是一个很好的原则,但不是一个定律.您不想不惜任何代价遵循它.看看应用它的优点和缺点.有时,将一个类分解为更小的类可以让您更好地控制责任,但这会牺牲这些类之间的大量通信.在您的示例中,您可能还要为资源加载,缓存,映射,保存等实现不同的类.但是如果每个类需要与其他类进行通信以执行其工作,那么分解不值得做,因为它需要高耦合,这很糟糕; 把它全部放在一个班级里.

有时我认为设计模式给软件开发世界带来了明显的损害!:-)

  • @ jeremy.mooer:+1"文档很好"并不意味着"文档太多"或"记录它的内容".它意味着它所说的:记录它*好*.精心挑选的类和方法名称加上一些额外的注释行,用于特别困难的逻辑代码部分,您需要通过"记录好"来实现我的意思.我完全同意你的看法! (3认同)
  • 我同意你的最后一段,但你选择了一个非常糟糕的例子.如果您的所有课程都需要与所有其他课程交谈以便执行他们的工作,那么您的整个架构都会被破坏.然后你有更多的理由来分解课程,而不是仅仅说"噢,不能完成,我将继续我的巨大的神级" (3认同)

Jah*_*ine 8

我认为你的解决方案不一定是错的.恕我直言,如果你考虑一下你从Aspect Oriented Programming的观点中所说的内容,它只是你的资源的一个方面,将由一个类处理.

虽然如果你认为你的代码库可能会发展成数百行,那么分解你的基础设施功能(域驱动设计模式)会更好.

我认为你的类是一个有凝聚力的类,并且manager名称并不总是一个坏的标志,除了它巩固许多可能不相关的类的控制流程,这些类彼此协作以完成任务.

如果您对缓存和映射的要求很容易发生变化,那么将您的问题分开可能会更好.

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