如何在Java中建模可选继承

huangapple go评论62阅读模式
英文:

How to model optional inheritance in Java

问题

以下是翻译好的内容:

这种情况下是否有可选继承的方式呢?

假设从这里开始:

(图片已省略)

注意:子类可能会多于4个。

现在有一个名为“Autonomous Transport”(自动驾驶交通工具)的可选功能,如下所示:

(图片已省略)

选项1:就像上面图片中的方式,我可以让所有子类从“Autonomous Transport”继承,但我不想这样做。比如说,火车不能是自动驾驶的。

选项2:不要将“Autonomous Transport”严格放在中间,而是让各个类根据需要进行继承(也许可以使用接口),比如“Car”(汽车)、“Autonomous Car”(自动驾驶汽车)、“Truck”(卡车)、“Autonomous Truck”(自动驾驶卡车)。但由于子类可能会超过4个,这不是一个吸引人的选项。

选项3:可能可以使用依赖注入,在需要的地方注入“Autonomous”功能,但不能添加任何类似于Dagger之类的框架。

还有其他的方法吗,可以在Java中实现得更清晰?基本上,如果“Train”(火车)不能是自动驾驶的,我不希望在那里涉及任何相关的业务逻辑。

英文:

Is there a way optional inheritance as described in the following case?

Say start with this:

如何在Java中建模可选继承

Note: there are can be more than 4 child classes.

Now there is an optional capability called "Autonomous Transport" as here.

如何在Java中建模可选继承

Option 1: As in this picture above I can have all child classes inherit from "Autonomous Transport" but I don't want that. Say, there cannot be an autonomous Train.

Option 2: Not have "Autonomous Transport" strictly in between but have individual classes inherit (may be with interface) like "Car", "Autonomous Car", "Truck", "Autonomous Truck" as needed. But not an attractive option as there are way more than 4 child classes

Option 3: Possibly, I can use dependency injection and inject "Autonomous" capability where needed but I cannot add any framework like dagger etc.

Are there any other ways, it can be done cleanly with Java? Basically, if "Train" cannot be autonomous, I do not want any related business logic there.

答案1

得分: 3

选项1

抽象类 Transport {
   foo();
} 

抽象类 AutomonousTransport 扩展自 Transport {
   bar();
}

类 Car 扩展自 AutonomousTransport {
   // 继承 foo 和 bar
}

类 Train 扩展自 Transport {
   // 只继承 foo(),因为 Train 仍然是一个 transport
}

使用这种方法,您需要决定从哪个类继承,以获取所需的功能。

这种方法的潜在缺点是,如果您有许多不同的功能(在 Java 中,您只能从一个类继承)。

为了解决这个问题,如果您只继承“功能”(行为),而不是状态,请考虑使用带有默认方法的接口,而不是抽象类。这在某种程度上类似于其他语言中的特性(Traits),但有一些限制:

接口 Transport {
   默认方法 foo () {...} 
}

接口 AutonomousTransport 扩展自 Transport {
   默认方法 bar() {}
}
接口 WheelSupportTransport 扩展自 Transport {
   默认方法 rotateWheelLeft() {...}
   默认方法 rotateWheelRight() {...}
}

类 Car 实现 AutonomousTransport, WheelSupportTransport  {
   
}

类 Train 实现 Transport {...}

选项2

抽象类 Transport {
   foo() 
}

终类 AutonomousStuff { // 终类以禁止继承
   bar()
}

类 Car 扩展自 Transport {
   AutonomousStuff autonomousStuff;
}

类 Train 扩展自 Transport {
   // 只有 foo
}

这种方法基于“优先使用组合而不是继承”的思想。您将行为添加到所需的类作为内部数据字段,并通过此字段获得所需的方法集(功能)。

选项3

抽象类 Transport {
   foo()
}

抽象类 AutonomousCapable 扩展自 Transport {
    私有最终 Transport transport;
    公共 AutonomousCapable(Transport transport) {
       this.transport  =  transport;
    }
    bar()

    foo() {
        transport.foo();
    }
    
}

类 Car 扩展自 Transport {}

类 Train 扩展自 Transport {} 

创建汽车时,使用 new AutonomousCapable(new Car())

这遵循“装饰器”(也称为包装器)模式的思想。您可以在运行时“装饰”对象(汽车),以获得额外的一组行为。

英文:

To keep it simple:

Option 1

abstract class Transport {
   foo();
} 

abstract class AutomonousTransport extends Transport {
   bar();
}

class Car extends AutonomousTransport {
   // inherits foo and bar
}

class Train extends Transport {
   //inherits only foo(), which is ok, since Train is still a transport 
}

With this approach you'll have to decide from which class to inherit so that you'll get the desired capabilities.

The potential drawback of this method is if you have many different capabilities like this (and in java you can extend only from one class).

To overcome this issue, if you only inherit the capability (behavior) and not the state, consider using interfaces with default methods instead of abstract classes. This works somewhat like Traits in other languages with some restrictions:

interface Transport {
   default foo () {...} 
}

interface AutonomousTransport extends Transport {
   default bar() {}
}
interface WheelSupportTransport extends Transport {
   default rotateWheelLeft() {...}
   default rotateWheelRight() {...}
}

class Car implements AutomonousTransport, WheelSupportTransport  {
   
}

class Train implements Transport {...}

Option 2

abstract class Transport {
   foo() 
}

final class AutonomousStuff { // final to prohibit inheritance from it
   bar()
}

class Car extends Transport {
   AutonomousStuff autonomousStuff;
}

class Train extends Transport {
   // only foo
}

This approach is based on "prefere composition over inheritance" idea. You add the behavior to the required class as an internal data field and gain the access to the required set of methods (capabilities) through this field.

Option 3

abstract class Transport {
   foo()
}

abstract class AutonomousCapable extends Transport {
    private final Transport transport;
    public AutonomouseCapable(Transport transport) {
       this.transport  =  transport;
    }
    bar()

    foo() {
        transport.foo();
    }
    
}

class Car extends Transport {}

class Train extends Transport {} 

When creating the car, use new AutonomousCapable(new Car())

This follows the idea of "decorator" (a.k.a. wrapper) pattern. You "decorate" the object (car) with additional set of behaviors in runtime.

答案2

得分: 1

如果自动驾驶是一个可选的能力,那么它实际上不是所有子类的普遍属性。

在我看来,可以有4个抽象类,如AbstractCarAbstractTruck等。然后,您可以针对每个抽象类有两个具体实现,比如AutonomousCarNonAutonomousCar。一个是自动驾驶的,另一个不是。

并且您可以为自动驾驶的类创建一个叫做IAutonomousTransport的标记接口。

当然,上述假设是您不想在类内部使用一个名为isAutonomous的简单标志,并根据它来处理功能。但这种方法不会具有多态性。

英文:

If Autonomous is an optional capability then it is actually not a generalized property of all its subclasses.

In my opinion, it would be 4 abstract classes AbstractCar, AbstractTruck etc. And then you can have two concrete implementations of each of these Abstract classes, say AutonomousCar and NonAutonomousCar. One autonomous and the other not.

And you can have a marker interface for the Autonomous classes called IAutonomousTransport

Of course, the above assumes that you don't want a simple flag called isAutonomous within your class and handle your functionality based on that. But this method wouldn't be polymorphic.

答案3

得分: 1

你应该在这里使用装饰者模式

public interface Transport {
    void foo();
}

public class AutonomousTransport implements Transport {
    public void foo() {
        // 自动运输实现
    }
}

public class Car implements Transport {
    private final Transport delegate;
    
    public Car(Transport delegate) {
        this.delegate = delegate;
    }
    
    public void foo() {
        if(delegate == null)
            // 汽车运输实现
        else
            delegate.foo();
    }
}

附言: 这个片段展示了一个简短的解决方案。可以有许多实现此模式的变体。

> 选项 1: 就像上面的图片一样,我可以让所有子类都继承自“自动运输”,但我不想这样做。比如,不能有自动列车。

考虑将继承替换为委托。在大多数情况下,委托更可取。

> 选项 2: 不是严格地在“自动运输”之间,而是让各个类继承(可能带有接口),比如“Car”、“自动汽车”、“卡车”、“自动卡车”等,根据需要添加。但这不是一个吸引人的选项,因为子类远远不止4个。

自动运输对我来说更像是行为,而不是属性。我确信它不应该在Transport层次结构中。

> 选项 3: 可能,我可以使用依赖注入,并在需要时注入“自动”功能,但我不能添加任何像Dagger之类的框架。

依赖注入是一种模式,而不是像Spring或Dagger这样的框架。如果您的类包含对另一个类的引用(无论是通过构造函数还是setter),那么实际上已经是依赖注入了。

英文:

You should use Decorator Pattern here:

public interface Transport {
    void foo();
}

public class AutonomousTransport implements Transport {
    public void foo() {
        // autonomous transport implementation
    }
}

public class Car implements Transport {
    private final Transport delegate;
    
    public Car(Transport delegate) {
        this.delegate delegate;
    }
    
    public void foo() {
        if(delegate == null)
            // car transport implementation
        else
            delegate.foo();
    }
    
}

P.S. This snippet shows you a brief solution. It could be many variants of implemnetation of this pattern.

> Option 1: As in this picture above I can have all child classes
> inherit from "Autonomous Transport" but I don't want that. Say, there
> cannot be an autonomous Train.

Think about replace inheritance to delegation. In most of the cases, delegation is more preferable.

> Option 2: Not have "Autonomous Transport" strictly in between but have
> individual classes inherit (may be with interface) like "Car",
> "Autonomous Car", "Truck", "Autonomous Truck" as needed. But not an
> attractive option as there are way more than 4 child classes

Autonomous Transport look to me like behavior, but not property. I am sure, that it should not be in the Transport hierarhy.

> Option 3: Possibly, I can use dependency injection and inject
> "Autonomous" capability where needed but I cannot add any framework
> like dagger etc.

Dipendency Injection is pattern but not a framework like Spring or Dagger. If your class contains linke to another class (does not matter via constructor or setter), de-facto this is DI already.

huangapple
  • 本文由 发表于 2020年9月5日 03:48:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/63747235.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定