在我第一次编程Java大约20年后,我希望我有多重继承。但我并不是因为我正在为这个具体问题寻找替代方案。
真正的应用程序是某种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
是从装饰对象中调用的,而装饰器只适用于来自"外部"的calles。所以我也必须将这些方法放在装饰器中,这也不是一个好主意。
因此,我可以使用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
}
}
答案 0 :(得分:10)
您可以使用模式策略来定义不同的行为,并使子类实现它们。
就像这张照片:
这是法语(下面的字典),但非常不言自明:
Personnage
继承的所有类都是视频游戏中使用的字符。EspritCombatif
,Deplacement
,Soin
)的所有类都定义了接口中的方法。他们是行为。Personnage
类包含右侧定义的每个接口的对象。Personnage
的子类)通过在构造函数中执行combat = new CombatCouteau();
来选择要实现的代码。因此,如果您只想改变所有与刀战斗的人的行为,您只需更改CombatCouteau
中的代码。
字典:
答案 1 :(得分:4)
Compositor
会这么做吗?它不能平稳地转化为汽车世界,但看起来适合您的任务:
public class FireTruck implements Car {
public FireTruck( List<? extends Car> behaviors ) {
this.behaviors = behaviors;
}
// I need to call the super method
@Override
public String doSteer( String where ) {
String result = "":
for (Car behavior : behaviors) result += behavior.doSteer(where);
// post-process behavior some how to cut out infixes;
}
}
我假设您的真实应用doSteer
适用于某个域对象,而不是String
,因此域对象的方法集应该足够丰富,以便在{{1方法。
答案 2 :(得分:4)
如果你不得不进行大规模的重构 - 解决这个复杂问题的一个好方法是分离状态和功能。只记得Java中的Object-Methods如何在幕后工作:基本上,对象 - 函数是一个静态函数,第一个参数是&#34;这个&#34;。 &#34;这&#34;参数是一个具有所需属性的状态对象。功能并不一定要与此绑定。
看起来像这样:
class CarState {
public float fuel;
public String name;
}
class BasicCarFunctionality {
public static void accelerate( CarState car ) {
System.out.println( "accelerating" );
}
}
class SportscarFunctionality {
public static void drive( CarState car, String how ) {
// Here you can reference Basic-Behaviour if you want
BasicCarFunctionality.accelerate( car );
System.out.println( car.name + " drive " + how );
}
}
class TruckFunctionality {
public static void steer( CarState car, String how ) {
System.out.println( car.name + " steer " + how );
}
}
interface SportsCar {
void doDrive( String how );
}
interface Truck {
void doSteer( String how );
}
class Firewagon implements SportsCar, Truck {
private CarState car = new CarState();
@Override
public void doDrive( String how ) {
SportscarFunctionality.drive( car, how );
}
@Override
public void doSteer( String how ) {
TruckFunctionality.steer( car, how );
}
}
如果您需要为您的火车提供额外的状态属性,而您在每辆车中都不需要这些属性,则可以使用新的State对象组成您的状态:
class FirewagonExtraState {
public float waterAmount;
public boolean sirenActive;
}
// And ammend the Firewagon Class:
class Firewagon implements SportsCar, Truck {
private CarState car = new CarState();
private FirewagonExtraState firewagon = new FirewagonExtraState();
@Override
public void doDrive( String how ) {
FirewagonFunctionality.activateHorn( firewagon );
SportscarFunctionality.drive( car, how );
}
@Override
public void doSteer( String how ) {
TruckFunctionality.steer( car, how );
}
}
答案 3 :(得分:2)
我不确定这个比喻是否足以给你一个好的答案..
在Java中处理多重继承问题的最基本方法是使用接口,然后使用合成委托行为。
汽车和卡车都有转向和加速,但是卡车不是汽车,不应仅仅因为某些实施是共享的而继承了它的行为。将共享实现拉出到更有意义的类(转向柱,传动系,等等),然后从汽车和卡车委托给它。
使用功能界面可以减少麻烦,但是您不需要Java 8来解决问题。
答案 4 :(得分:1)
这个怎么样:
public class SportsCar implements Car {
private final BasicCar basicCar;
public SportsCar( String name ) {
this.basicCar = new BasicCar(name);
}
public SportsCar( BasicCar basicCar ) {
this.basicCar = basicCar;
}
@Override
public String accelerate() {
return basicCar.accelerate() + " fastly";
}
@Override
public String decelerate() {
return basicCar.decelerate() + " fastly";
}
@Override
public String steerLeft(){
return basicCar.steerLeft() + " fastly";
}
@Override
public String steerRight(){
return basicCar.steerLeft() + " fastly";
};
}
public class Truck implements Car {
private final BasicCar basicCar;
public Truck( String name ) {
this.basicCar = new BasicCar(name);
}
public Truck( BasicCar basicCar ) {
this.basicCar = basicCar;
}
@Override
public String accelerate() {
return basicCar.accelerate() + " carefully";
}
@Override
public String decelerate() {
return basicCar.decelerate() + " carefully";
}
@Override
public String steerLeft(){
return basicCar.steerLeft() + " carefully";
}
@Override
public String steerRight(){
return basicCar.steerLeft() + " carefully";
};
}
现在为FireTruck
类
public class FireTruck implements Car {
Collection<Car> behaviors;
BasicCar basicCar;
public FireTruck(String name ) {
this.behaviors = new ArrayList<String>();
this.basicCar = new BasicCar(name);
this.behaviors.Add(new SportsCar(this.basicCar));
this.behaviors.Add(new Truck(this.basicCar));
}
@Override
public String accelerate() {
StringBuilder result = new StringBuilder();
for(Car c : behaviors){
result.append(c.accelerate());
}
//and if I wanted to do my own thing here as a 'FireTruck' I could, something like :
String myOwnAction = basicCar.accelerate() + " sounding alarms and flashing red light";
result.append(myOwnAction);
}
//same for other methods : decelerate, steerLeft and steerRight
}
答案 5 :(得分:0)
前段时间我问过一个非常相似的问题......也许你会觉得它很有用:
A Collection of an Abstract Class (or something like that...)