面向对象设计为什么我们需要Bird类的组合?

时间:2017-05-11 15:35:49

标签: class oop design-patterns composition object-oriented-analysis

最近我在一次采访中被问到一个设计鸟类飞行模拟器的问题。 我继续思考模拟器类的策略模式以及气压,风速等属性。一种方法可以获取鸟类物体和时间,并返回x,y,z坐标。 e.g。

class Simulator
 attr_accesor :bird, :air_pressure, :wind_velocity

 def map_coordinates(bird, time)
  ...
 end
 ...
end

然后考虑鸟类:

对于鸟可以飞/不飞属性我想到了一个布尔变量,它将在初始化时设置。例如:

class Bird
 attr_accessor :weight, :wing_dimension, :canfly, :height....

 def initialize(weight, wing_dimension, canfly, height)
  @weight = weight
  @wing_dimension = wing_dimension
  @canfly = canfly
  @height = height
 end 
end

我的问题是从OOD的角度来看,它说Bird类应该使用组合并使用类来封装类中所需的属性。 https://www.safaribooksonline.com/library/view/head-first-design/0596007124/ch01.html

那么,我真的需要一个类来映射canfly行为吗?在创建Bird对象时,我不能在这种情况下初始化一个布尔字段。

为什么这不是一个好的设计? 如果没有,最好的方法是什么?为什么?

2 个答案:

答案 0 :(得分:1)

就OOD而言,重要的是在关联/聚合,继承,组合和使用之间进行比较。在组合关系中,类应使用类的方法 new 创建对象实例。

鸟类具有特定的重量和高度,就鸟的构成而言,鸟有两个翅膀和一个峰值,可能是不同的类别。在Wing类中,wing_dimension属性应作为聚合关系包含在内,作为鸟类中的权重和高度。

class Bird
 attr_accessor :weight, :height, :rightWing, :leftWing, :peak

 def initialize(weight, height)
  @weight = weight
  @height = height
  rightWing = Wing. new
  leftWing = Wing. new
  peak = Peak.new
 end 
end

例如,在Simulator类中,如果您想要设计一个飞行模拟器,则此属性需要在不同的类中是通用的。

总而言之,如果在一般类之间存在继承关系,例如" Animal"使用鸟和苍蝇(昆虫),你可以在 def 中建立一个聚合关系,并且可以作为动物类的一个attrinute。

class Simulator
 attr_accesor :animal, :air_pressure, :wind_velocity

 def map_coordinates(animal, time)
  ...
 end
 ...
end

答案 1 :(得分:1)

  

那么,我真的需要一个类来映射canfly行为吗?在创建Bird对象时,我是否只能在这种情况下初始化一个布尔字段?

     

为什么这不是一个好的设计?如果没有,最好的方法是什么?为什么?

关于你的第一个问题:"我真的需要......?"这是一个真的好 题。在面向对象设计方面,这是您需要自问的问题。事实上,这正是设计决策的好坏。

事实上你也找到了一个试探性的解决方案"我不能......?"意味着您已经确定了可以使用二进制解决方案解决的 ONE 小问题。 bool canfly? true:false

让我们假设你已经看了大局。你想象你的" SIMULATOR"会有各种各样的鸟类,甚至是鸟类 无法飞行,以及那些 TYPICAL 鸟类。

最后,你会得到另外三个非常棒的问题 我不知道你是否想知道你是否直接将这些问题从OOA& amp; D教科书。

1)为什么这不是一个好的设计?

2)什么是更好的设计?

3)为什么第二个设计会优于第一个设计

好的,我会在这里尽力而为。我将尝试用你的方法来说明这些问题,以及你所做的方式。看看所有这些问题所带来的微小的足迹,与巨大的足迹相比,在我的帖子中做出来,试图填写在所有这些空白中,因为你不知道这些问题会产生多少答案(我也不知道)。这恰好是一个的答案。伙计,我希望这不会成为一个庞大的混乱。(那是另一个)

我想首先,我想澄清一个非常重要的区别 这些问题的性质与您期望在代数教科书中找到答案的问题的性质不同。代数是 HOW 。我发现为什么
在你进入微积分之前,在代数中没有任何意义。

为什么不是这样... 我应该采用什么样的 ... 如何更好...... 为什么那样更好......? 为什么我应该关心吗? 这些是您在哲学教科书中找到答案的问题。它们也是OOD的合适种类,因为OOD更像是一种哲学而非软科学。"这是我的观点,其他人持有这种观点,但有些人认为不然。听起来好吗具体

有趣的是,这是OOD中用于区分派生类和抽象类或接口的术语。这是结果,但 NOT 设计。在我看来,理解首先与任何具体的设计一样重要,如果不是更多,有些人可能试图将其作为一个好的答案。

我也问一个问题。您希望在代码库或我的巨大足迹中拥有微小足迹吗?因为你可以做你想做的事,这是你的选择。但是,让我指出可能会改变你的想法的东西。我可以创建一个接口让我说,我 可能会这样称呼它。

公共接口IEveryPossibleFlyingOperationYouOrAnyoneElseMightImagine {}; 你可能会说:这是一个非常漫长且过于描述性的命名约定!!! 我会回复:是的,但你甚至无法想象界面有多少东西。 ... 此外,我只需要写一次,因为那时我可以这样做...
IEveryPossibleFlyingOperationYouOrAnyoneElseMightImagine fly ;

然后我会在我的代码库中放置那个小小的 fly (也就是碰巧飞过的昆虫。)。然后,我会关闭它,并且希望永远不必再打开它。

此外,属于该接口的所有东西,你都不知道,因为它已被抽象掉,并且与其他类似的东西松散耦合,以便将来可能的扩展,永远不会破坏你的代码库。怎么可能呢?这是一只小小的苍蝇。

你知道这个答案有多长,而且它只是在你向我保证的实际问题的表面上划掉了。

现在,我会尝试给你一些更具体的东西,虽然它不足以满足你在这里提出的所有问题。

总的来说,OOP是关于很多事情的,这一点,我希望至少在某种意义上是一个原则。如果学习并遵循该原则,您将永远不会在代码库中占据我的足迹。

这个界面的背后隐藏着什么是你的客户永远不会知道的东西,但我向你保证,它的组合方式使它非常通用和适应性,因为我根据尝试建造它并证明了其他人比我聪明的原则和模式。

即使他们不了解这种范式的所有可能性,因为有太多不可数。他们无论如何都不在乎,因为他们正在忙着解决其他设计问题,通过混合和匹配原则和模式来解决非常简单的复杂问题。

另外,下次你开始设计一些东西时,你可以将那个小小的苍蝇放在那里并在那里使用它,并且将会有,只有一个地方可以维持和改善所有这一切在那个小小的苍蝇身后。

我知道这可能不是你想要的答案,或者你已经得到了它,这将是非常棒的。我花了很长时间才弄清楚对象到底是什么......但是一旦它被点击,在一位非常聪明的教授的帮助下,他向我展示了我试图在这里展示的内容;哦..  还有一本叫四人帮的书;然后我就能开始了,我只希望我也明白这一点。

我想如果你回头看看那篇文章,你就能弄清楚其他答案是什么,我只回答了那个简单的(或尝试过)。我看着它,所有信息都在那里。可能你需要以稍微不同的方式看待它,但如果你真的想知道,你会得到它。

对不起,但这是我能做的最好的,同时要诚实。如果有人试图告诉你 HOW 是答案,而不是为什么,请不要听他们,因为他们可能也不理解,但不是因为它很难。这是因为他们并没有像你在这里那样开始问正确的问题。我希望你好,并希望有其他人能够比我更好地解释它。 +1)要问所有正确的问题!