面向对象编程:抽象化应该到何种程度?

9

在编写代码时,何时停止抽象并开始编写合理的代码?有许多“企业代码”的例子,比如数十个文件的“FizzBuzz”程序...即使像实时战略游戏这样简单的东西也可能会有:

class Player {} ;/// contains Weapons
class Weapons{} ;/// contains BulletTypes
class BulletType{} ;///contains descriptions of Bullets 
class Bullet{} ;///extends PlaceableObject and RenderableObject which can be placed/drawn respectively
class PlaceableObject{} ;///has x,y,z, coords
class RenderableObject{} ;///an object with a draw() command
class MovingObject{}; ///an object with a move() function

等等...这可能会变成一场噩梦。这可以被推到其逻辑极端,就像函数式编程可以被推到只有变量、函数应用和匿名函数定义的语言的极端(虽然我必须承认这稍微更优雅一些)...

对于这个话题有什么明智的建议吗?

3个回答

21
  1. YAGNI (You Ain't Gotta Need It). 不要创建没有立即使用或明显原因的抽象化。这样,你会有一个简单的东西,可能会变得更加复杂,而不是一个复杂的东西,你必须努力使其更简单,但失去原本的目的。
  2. 确保这些抽象化是有意义的。如果它们与现实太远,太难证明...就放弃吧。
  3. 让解决方案自然而然地流畅。一直持续改进,直到做到为止。然后,对于一个陌生的人来说,这个解决方案应该是如此显然,以至于他会惊呼:“你怎么能用其他方式实现呢?”
  4. 不要试图预测未来,你无法预测。如果你试图覆盖所有可能出现的情况,你很快就会发现第11个及更多的情况,而且由于之前遇到的10个情况,它将更难实施。让它简单易于适应。 软件需要改变,但是适应性(灵活性)通常比试图预先覆盖所有可能情况更好的策略。

让解决方案感觉自然。一直努力工作,直到它变得自然为止 - 完美的规则!+1 - TT_ stands with Russia

3
也许这个问题应该是“从哪里开始抽象化”。 你引用的例子是一个经典的例子,表明没有足够的思考对象实际上是什么,因为它们几乎都是相同的 - 可能最好表示为单个“GameObject”。 我也避免通过对象属性来进行子类划分。对于StaticGameObject和DynamicGameObject可能看起来很合乎逻辑,但更好的表示方式可能是容器放置 - 即两个列表,一个用于静态对象,一个用于动态对象,从而允许其他逻辑定义操作,而不是对象本身负责控制其范围之外的东西。 有时候很难确定一组要在对象中表示的事物共享什么 - 但值得做。

0

我相信,标准可以从对抽象概念的明确定义中推导出来。

你在引用面向对象编程范式中的抽象概念,这里有三个原则:'抽象' - '封装' - '信息隐藏或可见性'

抽象是选择哪些对象属性与您的系统相关,哪些必须完全忽略的过程。

也就是说,抽象限制并不关注您定义的概念数量(玩家、武器、子弹等),而是关注您选择将哪些内容放入这些概念中。

它基本上是一种 分类,您将只从概念中考虑对您需要定义的服务有用的内容。

因此,编写健壮代码的好方法之一可能是首先考虑API,正如eclipse程序所建议的那样:首先考虑API

的确,"良好的API需要设计迭代",这意味着您在问题中提到的对象列表将随着所需API本身的精化而精化。

此外,API 意味着具有明确定义的组件边界和依赖关系(如“核心-播放器-vs.UI-RenderableObject-”),这意味着您提到的非常详细的列表不能被视为一个漫长无尽的概念列表,而必须从应用程序架构的角度清晰地分组为不同的功能范围(或功能组件)。
由于 API 存在是为了满足客户需求,因此您只会保留那些对客户有意义的对象。其他对象应该在“内部”包中,并且永远不应该被应用程序的任何其他部分直接引用。
考虑到这一点,@phjr 的建议就变得非常合理了 ;)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接