JAVA - 扩展vs接口 - 战略设计模式

时间:2015-03-17 04:35:19

标签: java multiple-inheritance code-reuse

我有一个多个具体类extends多个Abstract类的场景。我无法想出一个干净的结构,减少文件数量并避免代码重复。

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

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

编辑: 有几个传感器视图实现了Abstract视图类。每个传感器的calculate()方法不同。为简单起见,我刚刚列出了3个具体的类。同样,您将拥有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()
    }
}

3 个答案:

答案 0 :(得分:2)

策略设计模式会对您有所帮助。那么你应该记住一件事。

  

尽可能使用较少 extends关键字,最好使用接口合成

<强>解决方案:

封装calculate(),因为calculate()将来可能会发生变化,并且它有不同的实现。

<强>过程:

1)创建一个CalcInterface的接口calculate()

2)通过3个不同的类别CalcInterfaceCAnalogTempCalcCDigitalTempCalc实施CCustomTempCalc。然后在每个班级中实施calculate()

3)现在是composition的时间。假设您有Sensor类(主类)...然后创建类型为CalcInterface的对象。 PS:所有人都会display()

4)现在制作3个不同的班级,extends SensorAnalogSensorTempSensorCustomSensor ......

5)现在,在运行时,您将创建任何类型的CAnalogTempCalcCDigitalTempCalcCCustomTempCalc)对象。

编辑:

以下是类图,我对艺术并不擅长...但是这个图将让你对类和接口以及如何有效地使用它们有所了解。

enter image description here

现在,您可以通过实施CalcInterface ...

来实现任意数量的 CustomCalcuations

这是 POWER 以适应变化,而不会通过遵循策略设计模式更改您的当前实施

答案 1 :(得分:0)

我会将Sensor实施与View分开。传感器不需要知道视图存在。我将使用方法Sensor创建一个calculate()接口,返回一些结果(我在示例中使用了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);

这样,每个传感器都有一个具体的类,每个视图都有一个具体的类。如果 n 是视图数量且 m 是传感器数量,则总计 n + m 。通过模拟,数字和自定义视图,以及温度,电压和电流传感器,您将获得6个类别。

相反,通过为每个视图为每个传感器创建一个具体类,正如您所做的那样,您将获得 n * m 具体类。在上面的例子中,总数将是9,不包括3个抽象视图类。

答案 2 :(得分:0)

我唯一能看到的是您可以在public abstract void calculate()课程中提供CView的实施。如果任何类想要覆盖它,则覆盖它