如果它允许更轻松地解决另一个问题,是否可以散发出代码的味道?[关闭]


31

我和一群朋友在过去的一段时间里一直在从事一个项目,我们想发明一种很好的面向对象的方法来表示特定于我们产品的方案。基本上,我们正在开发东方风格的 子弹地狱游戏,我们希望建立一个系统,在其中可以轻松表示我们可以梦想的子弹的任何可能行为。

这就是我们所做的;我们制作了一个非常优雅的架构,使我们可以将项目符号的行为划分为不同的组件,这些组件可以随意附加到项目符号实例上,类似于Unity的组件系统。它工作得很好,易于扩展,灵活并且覆盖了我们的所有基础,但是存在一个小问题。

我们的应用程序还涉及大量的程序生成,即我们以程序方式生成项目符号的行为。为什么这是个问题?好吧,我们的OOP解决方案虽然表现优雅,但是代表人的举止却很复杂,如果没有人使用它,工作起来会有些复杂。人类足够聪明,可以想到既合理又明智的问题解决方案。程序生成算法还不那么聪明,我们发现很难实现一个充分利用OOP架构的AI。诚然,该体系结构的一个缺陷是并非在所有情况下都直观。

因此,为了解决此问题,我们基本上将不同组件提供的所有行为都推到了bullet类中,这样我们可以想像到的一切都直接在每个bullet实例中提供,而与其他关联的组件实例不同。这使我们的过程生成算法更容易使用,但是现在我们的bullet类是一个巨大的上帝对象。到目前为止,它很容易成为程序中最大的类,它的代码量是其他任何代码的五倍以上。维护也有点麻烦。

可以让我们的一个类变成一个上帝对象,只是为了使其更容易处理另一个问题吗?通常,如果它允许更轻松地解决其他问题,代码中是否会有代码味道是可以的吗?


1
好吧...这很难回答。我认为没有。特别是如果您与其他人一起工作。如果您一个人工作,您可以做任何您想做的事。但总的来说,这取决于您与谁一起工作。
Sarcastic Potato

13
“如果它是愚蠢的,并且有效;那不是愚蠢的。” 话虽如此,您仍然必须考虑即使它完全按照您的要求工作,您是否也因为决定如何修复它而使将来无法对该神类进行编码。
平坦

8
闻起来并知道自己发臭,然后闻起来只有别人注意才更好。:)
Reactgular 2015年

1
听起来您需要一个适配器类,该适配器类为您的过程代码提供非OO接口,因此您可以使其余代码保持整洁。
nikie 2015年

1
听起来您构建了一个很棒的系统,并决定将其全部丢给地狱,但现在它在一项功能上无法按预期工作。那真的是你想要的吗?为您的工作感到骄傲!
2015年

Answers:


74

在构建实际程序时,通常需要在一方面保持务实与另一方面保持100%的清洁之间进行权衡。如果保持清洁禁止您及时运送产品,那么最好带些胶带将可怜的东西拿出门。

就是说,您的描述听起来不一样-听起来您将不会添加一点胶带,听起来您将毁了整个体系结构,因为您看起来不够长且很难找到更好的解决方案。因此,与其在PSE上寻找能给您带来福气的人,不如问一个更深层次的问题,并在其中描述您所遇到的问题的详细信息,然后看看是否有人为您提供了一个避开神灵的想法,一流的方法。

也许子弹类可以设计成与其他许多类一起使用,所以子弹类变得更小。也许策略模式可以提供帮助,因此项目符号可以将不同的行为委派给不同的策略对象。也许您只需要在子弹组件和过程生成器之间使用一个适配器即可。但老实说,在不了解系统详细信息的情况下,人们只能四处猜测。


6
只是为了重申这个答案,我将用两个相同的建议来写一些东西。关于最后一段,OP所描述的内容本身似乎是一种代码味道,表明需要另一种间接方式。无论是更好的工厂级别,外观还是AI可以为其生成的完整的DSL,都由OP决定。
Daniel B

2
关于Facade / Strategy的好建议,可以将代码分成较小的块。尽管不了解更多详细信息,但很难知道建议什么。
user949300

25

有趣的问题。由于以前的经历,我有点偏见,这促使我回答“否”。

简短的回答:我们永不停止学习。当您碰到这样的墙时,这是提高您的建筑/设计技能的机会,而不是增加代码味道的借口。

较长的版本是,我现在在工作中的项目中曾多次被问过类似的问题,但是不可避免的是,我们最终对这个问题进行了更深入的讨论,然后最初的提问者就赞扬了它。您想要包括诸如根本原因分析之类的心态。

我发现“ 5个为什么”特别有用。您在这里的解释就像第一个原因一样:

  • “我们现在有这个神课” 为什么?
  • “因为它简化了程序生成算法”

简化后到底是什么?为什么会这样呢?继续沿着这条路线前进,通常会发生的是,您开始认识到一些更根本的问题,但是同时,它们也为您提供了更根本的解决方案。

长话短说,在更深入地思考手头的问题,尤其是其原因之后,以我的经验,最初的问题最终变得空洞,对所有参与者完全没有兴趣。如果您有疑问,请挑战它们,或者它们消失了,或者您会知道该做什么。提醒您,在我看来,对代码/设计有这些疑问是一个好兆头。其他人称之为直觉,但是要挑战这些问题,您必须首先意识到它们。既然您迈出了第一步,那么恭喜!现在下去兔子洞...


9

拥有这样的上帝类永远是不希望的,因为这不仅意味着您的子弹现在是整体对象,而且过程生成算法也是如此。

第一步将是分析,为什么您的AI确实在处理模式复杂性方面确实遇到了这么多麻烦?

您是否有偶然的机会也尝试将您的AI变成神类对象,并且充分了解每个可能属性的语义?如果您这样做,那就是问题的根源。

解决方案不是将所有策略都集成到子弹类本身,而是将有关AI的提示从AI核心转移到策略实现本身。

这将为您提供您最初希望的灵活性,包括根据需要通过新策略扩展系统的选项,而不必担心会因传统行为而产生副作用。

相反,您现在遇到了与上帝对象相关的所有问题:不仅您的上帝类本身很难理解,难以调试,而且对于访问此类上帝类的所有其他组件也是如此。由于缺乏抽象,您的AI现在势必会变成类似复杂性的可憎对象,因为它现在必须了解所有冗余的单个属性。

即使是现在,您也已经遇到维护问题。这些问题变得越来越严重,特别是一旦您松开仍然具有该班级工作方式认知模型的团队成员。

到目前为止,我遇到的每个使用此类God类或God函数的项目都被完全从头重写或终止了,没有例外。


在关于应使用多大或复杂的类的讨论中,经常缺少的一件事是“应将持有类型X的引用的代码进行多少处理”与“在类文件中应包含许多逻辑以区分”之间的区别。 X”。如果客户可能拥有支持各种功能的对象的集合(例如“可疑”),并且经常发现自己想要让集合的所有成员“例如可能的话可疑,否则什么也不做”,那么可以使用一个接口结合了许多这样的方法可能比尝试拆分接口更有帮助。
supercat 2015年

有了这样的接口,就可以使代码封装具有任何功能组合的对象,而不必分别处理不同的组合。隔离接口将有必要编写许多不同的代理类,因为不能使用支持方法X的类型的代理来包装不能X的对象,而可以使用不能包装X的对象来代理。即使包装了可以支持它的对象,也无法公开方法X。
supercat 2015年

8

自从时间的曙光以来,所有错误的代码背后都有一个故事,它逐步演变成合理的样子。您也不例外。编码员通过编码学习。您无法预见的问题的某些方面现在似乎很明显。您所做出的决定是完全合理的渐进式决定,但总体上将您的体系结构推向错误的方向。您需要确定并重新检查这些决定。

询问您办公室周围的人是否对如何解决有任何想法。在我工作过的大多数地方,大约有10-20%的程序员对此有真正的了解,并且一直在等待机会。找出那些人是谁。通常,历史上没有对当前体系结构进行投资的是您的新员工,他们最容易看到替代方案。将他们与您的一位退伍军人配对,您可能会惊讶于他们一起提出的想法。


2

在某些情况下,这绝对是可以接受的。但是,我很难相信没有使用过程生成和基于附件/组件的良好行为体系的良好解决方案。如果只是将所有行为都放到bullet项目中,那么God对象和纯净的架构版本之间就没有功能上的区别。是什么使您的程序生成算法难以使用?

我认为是一个新问题(也许在这里,或者在gamedev.stackexchange.com上?),您在其中概述与proc结合使用时体系结构遇到的问题。gen。,真的很有趣。如果您要提出新的问题,也请在这里告诉我们!


3
您能提供一个例子吗?在这种情况下,有一个神类既可以接受又可以接受,而该类不只是单个资源的自动编译吗?
2015年

可以接受时,我指的是“如果它允许更轻松地解决另一个问题,是否可以散发出代码的味道?” 通过使用合成,神类通常很容易解决。但是,是的,有某些代码气味绝对不值得总是100%消除。最后,需要一些实用主义才能完成工作:)。(这并不意味着我认为您应该一时兴起地提出最佳实践。我相信大多数软件公司最好严格地遵循最佳实践)。
罗伊(Roy T.)

0

为了获得启发,您可能想看一下函数式编程,或更确切地说,是紧密定制的类型。无法使用无法在无法使用的类型系统中表示事物的想法。例如,假设您的枪支具有“射击子弹”和“握住子弹”的组件。如果它们是两个独立的组件,那么这些配置就没有意义了-您可以拥有一把能发射子弹但没有任何子弹的枪,或者可以存储子弹但不发射子弹的枪。

在这种复杂性级别上,您正在考虑“对,一个人会发现这是无用的,并避免了不可能的组合”。更好的方法可能是使其完全无法执行此操作。例如,“拍摄项目符号”组件可能需要引用“保持项目符号”组件(或直接将其保留为一部分,尽管这是它自己的问题)。

尽管您的示例可能要复杂得多,但是关键仍然是限制可能的组合,增加约束。从某种意义上说,如果程序生成太复杂而无法正确执行,那么它可能也太复杂了。想想您在设计武器时会束缚自己的所有方式-您是否对自己说:“对,这把枪已经装有喷火器,没有必要加榴弹发射器”?您可以将其纳入启发式方法中。您可能想要使用一种概率机制,该机制要比给每个组件固定的机会要复杂一些-您可能有倾向于相互排斥的组件,或者倾向于相互配合的组件。

最后,考虑一下这是否实际上是一个足够大的问题。它破坏了游戏的乐趣吗?结果枪支是没用的还是功率过大的?多少?十分之一是荒谬的吗?像《无主之地》(带有程序生成的武器效果)之类的游戏通常会忽略无意义的效果组合-拥有16倍瞄准镜的shot弹枪有什么意义?然而,这在边境地区却经常发生。它只是在开怀大笑,而不是被认为是生成机制的失败:)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.