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

时间:2008-09-27 05:56:35

标签: java

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

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

Bar

这样好吗?使public class Foo { /* constructors, fields, method, logic and what-not */ } public class Bar extends Foo { /* nothing here but constructors */ } 成为复合类更好吗? e.g:

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 } Foo的示例,我的代码需要能够执行BarList<Foo>之类的操作。 List<Bar>无法进入Foo,反之亦然。

10 个答案:

答案 0 :(得分:14)

在我看来,如果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陈述。 : - )

答案 1 :(得分:3)

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

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

答案 2 :(得分:2)

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. */ }

由FooBarImplementation

组成的Foo和Bar

另一种可能性是让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。不要这样做,你将失去对象之间的差异,这就是你不想要的。

不要使用布尔值和whataver类型字段

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

答案 3 :(得分:1)

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

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

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

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

答案 4 :(得分:1)

基本上您需要应用Strategy Pattern

答案 5 :(得分:0)

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

答案 6 :(得分:0)

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

答案 7 :(得分:0)

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

Class MainStuff;
Class TypeA;
Class TypeB;

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

答案 8 :(得分:0)

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

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

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

答案 9 :(得分:0)

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