【发布时间】:2015-05-30 07:14:45
【问题描述】:
在 20 年左右第一次编写 Java 之后,我希望我有多重继承。但我没有,所以我正在为这个具体问题寻找替代方案。
真正的应用程序是某种 ERP,而且有些复杂,所以我尝试将这个问题转化为汽车。这只是到目前为止,但这是我能做的最好的。
让我们从描述汽车功能的界面开始:
public interface Car {
public String accelerate();
public String decelerate();
public String steerLeft();
public String steerRight();
}
现在我们有了一个基本的(但不是抽象的)实现:
public class BasicCar implements Car {
protected final String name;
public BasicCar( String name ) {
this.name = name;
}
// In the real word this method is important and does lots of stuff like calculations and caching
protected String doDrive( String how ) {
return name + " is " + how + "ing";
}
@Override
public String accelerate() {
return doDrive( "accelerat" );
}
@Override
public String decelerate() {
return doDrive( "decelerat" );
}
// This method is important, too
protected String doSteer( String where ) {
return name + " is steering to the " + where;
}
@Override
public String steerLeft() {
return doSteer( "left" );
}
@Override
public String steerRight() {
return doSteer( "right" );
}
}
在现实世界中,这本身就是 DAO 的外观。请注意,我需要有 doDrive 和 doSteer 方法,因为这是完成一些计算、翻译和缓存等实际工作的地方。
还有一些更具体的实现:
public class Sportscar extends BasicCar {
public Sportscar( String name ) {
super( name );
}
// I need to call the super method
@Override
public String doDrive( String how ) {
return super.doDrive( how ) + " fastly";
}
}
public class Truck extends BasicCar {
public Truck( String name ) {
super( name, new BasicMotor(), new TruckySteerer() );
}
// I need to call the super method
@Override
public String doSteer( String where ) {
return super.doSteer( where ) + " carefully";
}
}
我现在能做的是:
Car mcqueen = new Sportscar( "McQueen" );
mcqueen.steerLeft() //-> "McQueen is steering left"
mcqueen.accelerate() // -> "McQueen is accelerating fastly"
Car mack = new Truck( "Mack" );
mack.steerLeft() //-> "Mack is steering left carefully"
mack.accelerate() // -> "Mack is accelerating"
我现在想要做的是将这两者合二为一,共享它们的功能:
Car red = new Firetruck( "Red" );
red.steerLeft() //-> "Red is steering left *carefully*"
red.accelerate() // -> "Red is accelerating *fastly*"
我尝试/想到了什么
我可以将两者中的代码复制并粘贴到一个类中。但这绝不是一个好主意。而在实际应用程序中,这几乎是代码,所以这是一个更糟糕的主意。
我认为我在这里面临一些重大的重写/重构。
所以我可以将Sportscar 和Truck 设为装饰器,而Firetruck 则同时使用两者。但这不起作用,因为doSteer 和doDrive 是从被装饰对象内部调用的,而装饰器仅适用于来自“外部”的调用。所以我也必须将这些方法放在装饰器中,这也不是一个好主意。
所以我可以使用 Java8 的新奇特功能并将 doSteer 和 doDrive 委托给如下接口:
@FunctionalInterface
interface Driver {
public String doDrive( String where );
}
并将其提供给BasicCar 的构造函数
但后来(除了变得相当复杂和final 遇到一些其他相当讨厌的 Java 问题之外)我无法再以一种好的方式访问BasicCar 的状态了。
所以目前我在这里有点迷路。任何好的想法都会被欣赏。
编辑:举个例子,这在现实世界中的样子:doSteer 组可能类似于:
class ProductImpl {
String getTitle(){
return getField( "title" );
}
String getTeaser(){
return getField( "teaser" );
}
String getField( String name ){
Locale loc = configuredLocale();
Map vars = configuredVarialbes();
String value = getCached( name, loc );
value = translateVariables( value );
value = replaceVariables( value, vars );
// and more
}
}
【问题讨论】:
-
假设的
Firetruck组合需要访问Sportscar和Truck的哪些方法?只是你命名的protected,还是在现实世界中有很多这样的方法? -
嗨,鲍里斯。还有很多。真实的对象是具有许多属性的物品/产品。后代是产品,如“Set”(包含子产品)、“In set”(包含在集合中)、“matrix”(包含同一产品的变体)、“In matrix”(同一产品的变体)。尝试将“矩阵”放入“集合”或其他方式时会出现问题。所以真正的对象应该是
extends Product_InMatrix, Product_Set。真正的属性类似于availableAmout,它在“Sets”中将是其包含的产品数量的最小值。等等。 -
使用 Java8 功能并将它们全部转换为具有方法实现而不是抽象方法的接口有什么问题?
-
参见Stack Overflow: java traits or mixins pattern?,了解其他编程语言如何克服单继承限制的一些讨论。另一个相关技术是Stack Overflow: Java Aspect-Oriented Programming with Annotations
-
@Necreaux:几乎什么都没有。取决于你站在哪里。在我的情况下,始终如一地这样做(并且一致性几乎没有任何问题),这意味着拥有几乎与我想要覆盖的方法一样多的接口。 (约 20 个)。并且这些接口的实现数量相同(以及后代对象的数量更多)。这成为一个好主意,特别是如果您有许多可以由这些部分组成的后代类。如果只有少数,感觉不对。 (在我的情况下是 4-6)。 Gabriel 的建议也是如此,基本上就是这样。
标签: java inheritance design-patterns