我有一个多个具体类extends
多个Abstract
类的场景。我无法想出一个干净的结构,减少文件数量并避免代码重复。
要求是根据某些标准以不同方式显示各种传感器值。温度,电压,电流等传感器值可以包含anlaog小部件,数字标签或两者的组合。我有3个Abstract
类用于3种不同类型的视图。这3个Abstract
类实现了一个定义视图绘制方式的方法。每个传感器视图extends
3个Abstract
类,并实现读取传感器,执行一些工程转换和显示传感器值的方法。
这里的问题是具体类实现的代码无论它扩展的Abstract
类是什么都是相同的。 CAnalogTempView
,CDigitalTempView
和CCustomTempView
都具有相同的实现,但扩展了不同的类。
这看起来很尴尬。代码重复,源文件的数量增加了3倍。我在这里错过了一些简单的东西吗?有这样一个问题的模式吗?我可以在运行时extends
传感器视图类吗?实际的代码更复杂。为清楚起见,我简化了问题陈述。
编辑:
有几个传感器视图实现了Abstract
视图类。每个传感器的calculate()
方法不同。为简单起见,我刚刚列出了3个具体的类。同样,您将拥有CAnalogVoltageView
,CDigitalVoltageView
,CCustomVoltageView
和CAnalogCurrentView
,CDigitalCurrentView
,CCustomCurrentView
等等
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()
}
}
答案 0 :(得分:2)
策略设计模式会对您有所帮助。那么你应该记住一件事。
尽可能使用较少
extends
关键字,最好使用接口或合成。
<强>解决方案:强>
封装calculate()
,因为calculate()
将来可能会发生变化,并且它有不同的实现。
<强>过程:强>
1)创建一个CalcInterface
的接口calculate()
。
2)通过3个不同的类别CalcInterface
,CAnalogTempCalc
和CDigitalTempCalc
实施CCustomTempCalc
。然后在每个班级中实施calculate()
。
3)现在是composition
的时间。假设您有Sensor
类(主类)...然后创建类型为CalcInterface
的对象。 PS:所有人都会display()
。
4)现在制作3个不同的班级,extends Sensor
说AnalogSensor
,TempSensor
和CustomSensor
......
5)现在,在运行时,您将创建任何类型的CAnalogTempCalc
,CDigitalTempCalc
和CCustomTempCalc
)对象。
编辑:
以下是类图,我对艺术并不擅长...但是这个图将让你对类和接口以及如何有效地使用它们有所了解。
现在,您可以通过实施CalcInterface
...
这是 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
的实施。如果任何类想要覆盖它,则覆盖它