java - 我们如何通过使用泛型/任何其他方式删除代码冗余/改进代码

标签 java generics java-8

我的问题的示例如下所示。两个类CarBike具有相同的字段( wheelbodyColor )。

在类里面AssembleVehicle ,方法getDetails Car 几乎重复和Bike 。有没有办法消除冗余或提高编码标准?

class Vehicle {
    Car car;
    Bike bike;

    //setter & getter
}

class Car {
    String wheel;
    String bodyColor;
    
    //setter & getter
}

class Bike {
    String wheel;
    String bodyColor;
    
    //setter & getter
}

class AssembleVehicle {
    public void init(Vehicle v) {   
        getDetails(v.getCar);
        getDetails(v.getBike);
    }
    
    private void getDetails(Car c) {
        String wheel = c.wheel;
        String bodyColor = c.bodyColor;
    }
    
    private void getDetails(Bike c) {
        String wheel = c.wheel;
        String bodyColor = c.bodyColor;
    }
}

这里,我们如何删除 getDetails 的代码冗余?。我们可以只使用这个方法一次吗?

我对泛型的理解是:泛型允许您为您正在使用的任何类型自定义“泛型”方法或类。例如,假设您有一个将两个数字相加的方法。为了使用类型本身,您可能必须创建此方法的多个版本。

最佳答案

以这种方式思考 OOP 的重点是错误的。即使您解决了最初的问题,即拥有一辆内部装有汽车和自行车的车辆,带有车轮和 bodyColor 字段的车辆父类(super class)的“改进”模型也可能会被破坏(取决于您正在工作的实际领域) 。例如,自行车车轮和汽车车轮有很大不同,而雪橇是没有任何轮子的车辆。乍一看相似的事物并不总是适合纳入 super 类的候选者。

问题是,我们很容易假设,如果一个类别的两个示例具有一些共同的特征,那么这些特征对于该类别的所有成员都存在(顺便说一句,这种概括的倾向也可能是许多问题的原因社会)。

OOP 的力量并非来自提取父类(super class)(如 Vehicle)和“重用”某些字段。直接子类化是一种非常严厉的措施,不应轻易应用,因为它意味着所有当前和 future 的子类必须继承父类(super class)的完整契约(数据和行为)。一旦您想要添加新的子类并被迫做出异常(exception),您就知道模型是错误的。到那时改变它将会影响所有现有的子类。事实上,直接子类化几乎总是违反 open-closed principleSOLID design principles 组中的第二个.

一种更灵活的方法是提取接口(interface)来封装类类别的某些方面:

interface Wheeled {
    String getWheels();
}

class Car implements Wheeled {

    private String wheels;        

    @Override
    public String getWheels() {
        return wheels;
    }
}

class Bike implements Wheeled {

    private String wheels;        

    @Override
    public String getWheels() {
        return wheels;
    }
}

如果您只对轮子感兴趣,这将允许对汽车和自行车进行相同的处理:

List<Wheeled> wheeledVehicles = new ArrayList<>();
wheeledVehicles.add(new Car());
wheeledVehicles.add(new Bike());
String firstWheels = wheeledVehicles.get(0).getWheels());

如果您对车身颜色,甚至车轮和车身颜色感兴趣,您可以自由地使用界面:

interface Wheeled {
    String getWheels();
}

interface Coloured{
    String getBodyColour();
}

interface WheeledAndColoured extends Wheeled, Coloured {}

这允许:

List<WheeledAndColoured> wheeledAndColouredVehicles = new ArrayList<>();
wheeledAndColouredVehicles.add(new Car());
wheeledAndColouredVehicles.add(new Bike());

WheeledAndColoured first = wheeledAndColouredVehicles.get(0);
String firstWheels = first.getWheels());
String firstColour = first.getBodyColour());

如果你真的愿意,你可以将wheels字段提取到一个父类(super class)中,但是直接的 yield 是有限的。私有(private)字段是一个实现细节,将它们拉入父类(super class)当然不是那种会产生很大影响的重用类型。同时,它会在这些类之间创建非常强的依赖关系,并使 future 的更改变得更加困难。

也许如果您需要实现一些与轮子相关的“复杂”共享逻辑,那么是时候创建 Wheels 类了:

class Wheels {

    private String type;
    private int number;
    private BigDecimal price;
    
    public BigDecimal getReplacementCosts() {
        return price.multiply(BigDecimal.valueOf(number));
    }
}     

现在 Car 类可以与 Wheels 类协作作为其字段之一:

class Car implements Wheeled {

    private Wheels wheels;        

    @Override
    public String getWheels() {
        return wheels.getType();
    }

    public BigDecimal getMaintenanceCosts() {
        return wheels.getReplacementCosts();
    }
}           

请注意,因为我们没有将 Car 和 Bike 与公共(public)父类(super class)绑定(bind)在一起,所以我们不会被迫更改 Wheeled 接口(interface)或 Bike 类。如果您想将车轮逻辑添加到 Bike 中,那么您可以轻松地做到这一点,但您不会被迫这样做。如果车轮字段位于共享父类(super class) Vehicle 中,那么您就会这样做。

所以座右铭是:优先考虑协作而不是扩展,因为它更加灵活。

关于java - 我们如何通过使用泛型/任何其他方式删除代码冗余/改进代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70272726/

相关文章:

java - 如何避免在测试期间调用 spring AOP 切面

java - Android 设备提供不正确的 Displaymetrics

Scala:在依赖于路径的上下文中重用由依赖于路径的类型产生的泛型

java - 对于 Java 中的静态帮助器类,使用泛型还是对象类型更好?

generics - 如何在 Rust 中正确设置通用集合类型

java - 写一个从 servlet 到 JavaScript 的数组响应?

java - 在运行时编辑 i18 属性

java - CompletableFuture - 并行运行多个 rest 调用并获得不同的结果

arrays - Java 8 Streams - 从对象列表中获取不同的整数作为数组

java-8 - Wildfly 8.2/undertow 读取超时