JAVA - 扩展与接口 - 策略设计模式

JAVA - extends vs interface - Strategy design pattern

我有一个场景,其中多个具体 classes extends 多个 Abstract classes。我不知所措想出一个干净的结构,减少文件数量,避免代码重复。

要求根据某些标准以不同方式显示各种传感器值。温度、电压、电流等传感器值可以有一个 anlaog 小部件、一个数字标签或两者的组合。对于 3 种不同类型的视图,我有 3 Abstract classes。这 3 Abstract classes 实现了一个定义如何绘制视图的方法。每个传感器查看 extends 3 Abstract classes 并实现读取传感器的方法,执行一些工程转换并显示传感器值。 这里的问题是具体的 classes 实现的代码是相同的,无论它扩展什么 Abstract class。 CAnalogTempViewCDigitalTempViewCCustomTempView 都具有相同的实现,但扩展了不同的 classes。

这看起来很尴尬。代码重复并且源文件的数量增加了 3 倍。我在这里是否遗漏了一些简单的东西?有这样的问题的模式吗?我可以 extends 传感器在 运行 时间查看 classes 吗?实际代码更复杂。为了清楚起见,我过度简化了问题陈述。

编辑: 有几个传感器视图实现了 Abstract 视图 classes。每个传感器的 calculate() 方法不同。为了简单起见,我刚刚列出了 3 个具体的 classes。同样,你会有 CAnalogVoltageViewCDigitalVoltageViewCCustomVoltageViewCAnalogCurrentViewCDigitalCurrentViewCCustomCurrentView 等等

public abstract class CView
{
    public abstract void draw();
    public abstract void calculate();
}

public abstract class CAnalogView extends CView
{
    public void draw()
    {
         // draw specific to analog view
    }
}

public abstract class CDigitalView extends CView
{
    public void draw()
    {
        // draw specific to digital view
    }
}

public abstract class CCustomView extends CView
{
    public void draw()
    {
        // draw specific to custom view
    }
}

// concrete implementations
public class CAnalogTempView extends CAnalogView
{
    public void calculate()
    {
        // read and calculate sensor value here
    }
}

public class CDigitalTempView extends CDigitalView
{
    public void calculate()
    {
        // calculate here. same as CAnalogTempView::calculate()
    }
}

public class CCustomTempView extends CCustomView
{
    public void calculate()
    {
        // calculate here. same as CAnalogTempView::calculate()
    }
}

我会将 Sensor 实现与 View 分开。传感器不需要知道视图存在。我会创建一个 Sensor 接口,方法 calculate() 得到 returns 一些结果(我在示例中使用了 double):

public interface Sensor {
    double calculate();
}

public class TemperatureSensor implements Sensor {
    public double calculate() {
        // specific implementation for the temperature sensor
    }
}

并更改抽象 CView 以具有传感器的属性,以及 calculate() 的实现,仅显示特定传感器计算的结果。

public abstract class CView {
    private Sensor sensor;

    CView(Sensor sensor) {
        this.sensor = sensor;
    }

    public abstract void draw();

    public void calculate() {
        double result = this.sensor.calculate();
        // display the result
    }
}

public class CDigitalView extends CView {
    CDigitalView(Sensor sensor) {
        super(sensor);
    }

    public void draw() {
        // draw specific to digital view
    }
}

所以每次创建视图时,在构造函数中传递要显示的传感器,如下所示:

Sensor temperatureSensor = new TemperatureSensor();
CView digitalView = new CDigitalView(temperatureSensor);

这样,每个传感器都有一个具体的 class,每个视图都有一个具体的 class。如果 n 是视图数,m 是传感器数,则您的总数是 n + 。使用模拟、数字和自定义视图,加上温度、电压和电流传感器,您将获得 6 classes。

相比之下,通过为每个视图的每个传感器创建一个具体的 class,正如您所做的那样,您将得到 n * m 具体classes。在上面的示例中,总数为 9,不包括 3 个抽象视图 classes.

我唯一能看到的是您可以在 CView class 中提供 public abstract void calculate() 的实现。如果有 class 想要覆盖它,我会覆盖它

策略设计模式会帮助你。嗯,你应该记住一件事。

Use as less extends keyword as possible, better to use Interfaces or composition.

解法:

封装calculate(),因为calculate()将来可能会改变,它有不同的实现。

进程:

1) 创建一个界面 CalcInterfacecalculate().

2) 通过 3 个不同的 class 实现 CalcInterface,比如 CAnalogTempCalcCDigitalTempCalcCCustomTempCalc。然后在每个 class.

中实现 calculate()

3) 现在是 composition 的时候了。假设你有 Sensor class (main class) ...然后创建 CalcInterface 类型的对象。 PS:它将有display(),这对所有人都是通用的。

4) 现在制作 3 个不同的 classes,extends Sensor 表示 AnalogSensorTempSensorCustomSensor ...

5) 现在在运行时,您将生成任何类型的(CAnalogTempCalcCDigitalTempCalcCCustomTempCalc)对象。

编辑:

下面是 Class 图,我不擅长艺术...但是这个图会让你对 classes 和接口以及如何有效地使用它们有一些想法。

现在,只要实现 CalcInterface ...

,您就可以实现任意数量的 CustomCalcuations

这是 POWER 以在不改变当前实现的情况下适应变化 您通过遵循策略设计模式获得。