[英]Is it OK to have an 'empty' class that extends another class?
假设我有一个类Foo
,其中有一堆逻辑,另一个类Bar
基本相同。 但是,由于Foo
和Bar
是不同的(但相关的)实体,我需要从我的代码中明显区别(即我可以判断实例是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
}
你怎么看? 你如何处理这些'标记类'?
作为我的代码可能希望以不同方式处理Foo
和Bar
的示例,我的代码需要能够执行List<Foo>
和List<Bar>
。 Foo
无法进入List<Bar>
,反之亦然。
在我看来,最好是Foo
和Bar
子类化一个共同的祖先类(也许是AbstractFoo
),它具有所有功能。 Foo
和Bar
之间应该存在什么样的行为? 将差异编码为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类的含义。 他们代表什么,他们的目的是什么。 请澄清。
我可以想象您的每个解决方案和建议的解决方案都是正确的情况。
我将创建一个类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。
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. */
}
Shoudl Foo继承自Barn,就语言而言,Foo将是一个Bar。 不要这样做,你将失去对象之间的差异,这是你不想要的。
这是你可能遇到的最糟糕的想法。 Bjarne Stroustrup警告不要使用C ++的这种反模式,而C ++并不是关于OOP的。 所以我猜这种模式对Java来说更“反”...... :-)
如果有一天Foo
和Bar
可能在实现中出现分歧,那么你的问题就会得到解答 - 以任何最好的方式使用继承。
但是,如果你绝对肯定他们永远不会分歧,那么显然你正在寻找应该由一个类代表的东西,比如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.