繁体   English   中英

有一个扩展另一个类的“空”类是否可以?

[英]Is it OK to have an 'empty' class that extends another class?

假设我有一个类Foo ,其中有一堆逻辑,另一个类Bar基本相同。 但是,由于FooBar是不同的(但相关的)实体,我需要从我的代码中明显区别(即我可以判断实例是Foo还是Bar

当我在没有多想的情况下一起打击这个时,我最终得到了以下内容:

public class Foo {
  /* constructors, fields, method, logic and what-not */
}

public class Bar extends Foo {
  /* nothing here but constructors */ 
}

这个可以吗? 使Bar成为复合类更好吗? 例如:

public class Bar {
  private Foo foo;

  /* constructors and a bunch of wrapper methods that call
     into foo */
}

或者甚至,当我们在它的时候,更低技术的东西:

public class Foo {
  /* constructors, fields, method, logic and what-not */

  private boolean isABar; // Could be an enum
}

你怎么看? 你如何处理这些'标记类'?


作为我的代码可能希望以不同方式处理FooBar的示例,我的代码需要能够执行List<Foo>List<Bar> Foo无法进入List<Bar> ,反之亦然。

在我看来,最好是FooBar子类化一个共同的祖先类(也许是AbstractFoo ),它具有所有功能。 FooBar之间应该存在什么样的行为? 将差异编码为AbstractFoo的抽象方法,而不是在代码中使用if语句。

示例:而不是:

if (foo instanceof Bar) {
    // Do Bar-specific things
}

改为:

class Bar extends AbstractFoo {
    public void specialOp() {
        // Do Bar-specific things
    }
}

// ...
foo.specialOp();

这种方法的好处是,如果你需要第三个类,那就像Foo一样,但只有一点点差别,你不需要查看所有代码并添加编辑所有if语句。 :-)

这一切都取决于Foo和Bar类的含义。 他们代表什么,他们的目的是什么。 请澄清。

我可以想象您的每个解决方案和建议的解决方案都是正确的情况。

Foo和Bar继承自FooBarImplementation

我将创建一个类FooBarImplementation来实现Foo和Bar的常用功能。 Foo和Bar将从中衍生出来。 但是,在你的代码,从来没有使用类型FooBarImplementation。 我的Java时代有点落后于我,但我想必须有某种方法可以隐藏用户代码中的FooBarImplementation(使其受到保护,或者仅包装可见,具体取决于您的项目组织。这样,没有用户代码会混合Foo对于一个酒吧(反之亦然)?

class FooBarImplementation
{
   public void doSomething() { /* etc. */ }
   /* etc. */
}

class Foo inherits FooBarImplementation { /* etc. */ }
class Bar inherits FooBarImplementation { /* etc. */ }

Foo和Bar由FooBarImplementation组成

另一种可能性是让Foo和Bar将他们的每个方法转发到内部类(同样,FooBarImplementation)。 这样,用户代码就无法成为Foo和Bar。

class FooBarImplementation
{
   public void doSomething() { /* etc. */ }
   /* etc. */
}

class Foo
{
   private FooBarImplementation fooBarImplementation = new FooBarImplementation() ;

   public void doSomething() { this.fooBarImplementation.doSomething() ; }
   /* etc. */
}


class Bar
{
   private FooBarImplementation fooBarImplementation = new FooBarImplementation() ;

   public void doSomething() { this.fooBarImplementation.doSomething() ; }
   /* etc. */
}

不要让Foo从Bar继承(反之亦然)

Shoudl Foo继承自Barn,就语言而言,Foo将是一个Bar。 不要这样做,你将失去对象之间的差异,这是你不想要的。

不要使用boolean和whataver类型字段

这是你可能遇到的最糟糕的想法。 Bjarne Stroustrup警告不要使用C ++的这种反模式,而C ++并不是关于OOP的。 所以我猜这种模式对Java来说更“反”...... :-)

如果有一天FooBar可能在实现中出现分歧,那么你的问题就会得到解答 - 以任何最好的方式使用继承。

但是,如果你绝对肯定他们永远不会分歧,那么显然你正在寻找应该由一个类代表的东西,比如ThingThatIsEitherFooOrBar

并且使用该类创建,而不是像isFoo那样给它一个布尔属性,再看看为什么需要将Foo与Bar区isFoo来会好得多。 什么是Foos让你处理它们不同于酒吧? 想出来,并创建一个指定不同信息的属性。 Foos更大吗? 然后创建一个大小的属性(即使它是一个值为“Foo-sized”和“Bar-sized”的枚举)。

如果没有具体的Foo和Bar可能的例子,这就差不多了。

基本上你需要应用策略模式

绝对使用布尔属性。 这是最简单的解决方案,除非您预见到Bar类需要稍后更改它的界面(例如覆盖它的方法)。

继承是最好的。
使用布尔属性,类必须知道两种不同类型的对象的存在,并且这不容易扩展到两个以上。 而且,这种方法不会让你超载功能。
组合使您可以为所有函数编写包装器。

你的数据不够清晰,但根据我认为你需要的东西,我很困惑你为什么不简单地选择第四种方式:

Class MainStuff;
Class TypeA;
Class TypeB;

不要让TypeA和B从MainStuff继承,或者使MainStuff成为TypeA和TypeB的数据成员。 这取决于这3个类的含义。

正如其他人所说,这取决于,但如果你在Foo和Bar之间有共同的功能,并且功能上的差异可以表示为参数,那么我投票给子类。 这基本上就是我们在实际软件课程结束时所做的工作。

我们应该实现一个数独游戏,最后,我们有一个“AbstractPlayfield”,它能够将任意规则集应用于任意游戏场。 这个AbstractPlayfield由我们应该实现的各个变体子类化。 这些子类为抽象游戏场设置参数(主要是棋盘的规则和形状),一切都像魅力一样。 我们甚至在这些子类中得到了更多的继承,因为几个变体包含规则“数字必须在一行中唯一”和“数字在列中必须是唯一的”。
使用它,我们能够在大约3天内完成估计大约2个月的工作:)(他们用“测试那些微小的属性设置类来惹恼我们,因为你可能有错误!测试它们!测试他们!我们不在乎所有重要的逻辑都经过测试!“。)

另一方面,如果类Bar没有Bar的特殊功能,我没有看到添加它的重点 - 至少从你给我的数据。 如果你想根据类型和类型调度做一些操作可能有意义,但我无法从Foo和Bar中读到它。 在这种情况下,由于YAGNI,我不会创建Bar。

如果Foo和Bar之间没有行为差异,那么类名“Foo”就不够抽象。 确定Foo和Bar之间的通用抽象,并相应地重命名该类。 然后在类中提供一个成员字段,将实例标识为“Foo”,“Bar”等。如果要将可能的值限制为“Foo”和“Bar”,请使用枚举。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM