【问题标题】:Is it bad OOP practice to subclass MANY classes from a base class?从基类中继承许多类是不好的 OOP 实践吗?
【发布时间】:2014-03-31 19:08:50
【问题描述】:

我对这个网站比较陌生,所以如果我在发布问题时做错了什么,请告诉我,以便我下次修复它。

我很好奇从一个基类继承多个类是否是不好的 OOP 实践。这可能不太有意义,所以我将详细说明。

例如,假设您正在设计一款游戏,并且您可能会遇到几个不同的怪物。我会采取的方法是为普通怪物对象创建一个基本抽象类,然后使用新类从基类中继承所有特定类型的怪物。

我的一位导师告诉我,在这种情况下,你不应该依赖继承,因为怪物的数量会不断增长,类的数量会增加到难以跟踪所有的程度。他们中的一个,因此你将不得不在将来添加每个新类时重新编译程序。

我不明白为什么(或者即使)这是一件坏事。如果有人可以帮助我了解我的教授来自哪里,将不胜感激。

谢谢!

【问题讨论】:

  • 我会说你的建议是一种典型的方法,确实有意义。然而,这是否意味着您的教授错了:您每次添加另一个类时都必须重新编译您的程序。如果这是一个缺点,取决于您的情况,我们不知道。例如,如果您计划一个游戏应该不间断地运行或重新启动,则可能是这样。然后一种更动态的方法可能是有意义的,一种进入动态对象创建的方向。通常,此类细节也会影响实施的语言用户。
  • 有效的编程都是关于权衡的 - 几乎没有一种“最佳”方法。

标签: oop inheritance subclass


【解决方案1】:

如果怪物非常相似,唯一的区别是(例如)他们的名字,他们给予多少伤害,他们是什么颜色等等,那么这些差异可以反映在一个领域(在值中),可能不需要子分类。

但是,如果你的怪物与其他怪物有着根本的不同,那么就必须有非常不同的方法和逻辑,更具体地说,无法反映在字段,那么可能需要一个子类SpecialMonster

但同样,即使SpecialMonster 也可能不需要按单个怪物类型进行子分类,因为 它的 字段可能足以区分它们。 p>

虽然拥有一百万个特定怪物类型的子类是合法的,但当它可以简单地在新的 Monster 实例的字段中表达时,您不想处理所有重复的代码,例如

new Monster("Goob", WakeTime.NOCTURNAL, 35, new Weapon[]{sword, hammer, knittingNeedle});
new Monster("Mister Mxyzptlk", WakeTime.ANYTIME, 71, new Weapon[]{sword, mindMeld, cardboardCutter});

还有一个替代方案,你确实有很多类,但你不要将它们强加给你的用户,你也不会用它们把你的 API/JavaDoc 弄得乱七八糟。如果你的 Monster 恰好是一个抽象类

public abstract class Monster  {
   private final String name;
   ...
   public Monster(String name, int default_damage, WakeTime wake_time, Weapon[] weapons)  {
      this.name = name;
      ...
   }
   public String getName()  {
      return  name;
   }
   ...
   public abstract int getDamage(int hit_strength);
}

那么你可以有一个这样的怪物便利创造者:

/**
  <P>Convenience functions for creating new monsters of a specific type.</P>
 **/
public class NewMonsterOfType  {
  private NewMonsterOfType()  {
     throw  new IllegalStateException("Do not instantiate.");
  }
  /**
     <P>Creates a new monster that is nocturnal, has 35-default-damage, and whose weapens are: sword, hammer, knittingNeedle.</P>
   **/
  public static final GOOB = new GoobMonster();
  /**
     <P>Creates a new monster that can be awake at any time, has 71-default-damage, and whose weapens are: sword, mindMeld, cardboardCutter.</P>
   **/
  public static final MISTER_MXYZPTLK = new MisterMxyzptlkMonster();
}
class GoobMonster extends Monster  {
  public GoobMonster()  {
     super("Goob", WakeTime.NOCTURNAL, 35, new Weapon[]{sword, hammer, knittingNeedle});
  }
   public int getDamage(int hit_strength)  {
     return  (hit_strength < 70) ? getDefaultDamage() : (getDefaultDamage() * 2);
  }
}
class MisterMxyzptlkMonster extends Monster  {
  public GoobMonster()  {
     super("Mister Mxyzptlk", WakeTime.ANYTIME, 71, new Weapon[]{sword, mindMeld, cardboardCutter});
  }
   public int getDamage(int hit_strength)  {
     return  (hit_strength < 160) ? getDefaultDamage() + 10 : (getDefaultDamage() * 3);
  }
}

为了让这些私有(实际上是包保护的)类不会出现在您的 JavaDoc 中,您需要将其 access 设置为 protectedpublic

【讨论】:

  • @user3390653:如果这个答案对您有所帮助,请考虑通过点击绿色的大勾号投票并接受它作为您的答案。祝你好运,欢迎来到 stackoverflow!
  • 现在是blog post
【解决方案2】:

在你的场景中继承是很自然的,因为所有特定的怪物也是基础怪物:)。我实际上会在这里大量使用继承,因为可能特定的怪物确实具有必须被覆盖的特定行为。 MonsterA 可能通过爬行移动,而 MonsterB 可能通过飞行移动。基础 AMonster 将有一个抽象的 Move() 方法,由这些子类型实现。

这不是最终的答案,它在很大程度上取决于游戏的需求,但是,在简化的形式中,继承在这里是有意义的。怪物种类的数量可能会继续增长,但真的,它们都一样吗?怪物设计只是基于将一些预定义的数据/行为组合在一起?那么游戏就很简单了……

我真的觉得您的讲师不以编写游戏为生(我也没有,虽然我前段时间做过游戏),但他对为什么不应该使用继承的解释过于简单了。在应用中定义的类的数量从来都不是问题,如果遵守单一职责原则,则越多越好。

关于你必须重新编译你的应用程序......是的,当你修复一个错误时,你也必须重新编译它。 IMO,他给你的理由在这种情况下是无效的。他需要提出更好的论据。

同时,去继承。

【讨论】:

    【解决方案3】:

    理论问题需要理论答案:)。

    这不仅不好,而且毫无意义。您应该有有限数量的从其他类继承的“基”类,并且这些类应该由其他类组成(支持组合而不是继承)。

    因此,随着复杂性的增加,组成基类的类的数量应该会增加。不是基类本身的数量。

    就像在行业中一样。以机器为例,它们实际上是由大量的小零件组成的,其中一些小零件在不同的机器中是相同的。当您设计新机器时,您不会为它订购新的独特“基础”部件,只是为了为您的新机器命名。您使用市场上现有的零件并设计一些新零件(不是“基础”),只有当您找不到现有的对应物时...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-17
      • 2019-01-06
      • 1970-01-01
      • 2011-09-12
      • 2023-03-07
      • 1970-01-01
      相关资源
      最近更新 更多