我想知道是否应该更改我的某个项目的软件架构。
我正在为一个项目开发软件,其中双方(实际上是主机和设备)使用共享代码。这有助于共享数据,例如枚举可以存储在一个中心位置。
我正在使用我们称之为“频道”的设备和主机之间传输数据。每个通道必须在设备和主机端实现。我们有不同类型的通道,普通通道和传输测量数据的特殊通道。
我当前的解决方案在抽象基类中具有共享代码。从那里开始,代码在双方之间分开。事实证明,在某些情况下我们会共享代码但我们无法共享代码,我们必须在每一方面实现它。
DRY的原则(不要重复自己)说你不应该有两次代码。
我现在的想法是连接例如设备端的抽象测量通道和具有共享代码的抽象类中的主机端。这意味着,一旦我们为该通道创建设备或主机端的实际类,我们就必须隐藏另一方使用的功能。
这是可以接受的事情:
public abstract class ChannelAbstract
{
protected void ChannelAbstractMethodUsedByDeviceSide() { }
protected void ChannelAbstractMethodUsedByHostSide() { }
}
public abstract class MeasurementChannelAbstract : ChannelAbstract
{
protected void MeasurementChannelAbstractMethodUsedByDeviceSide() { }
protected void MeasurementChannelAbstractMethodUsedByHostSide() { }
}
public class DeviceMeasurementChannel : MeasurementChannelAbstract
{
public new void MeasurementChannelAbstractMethodUsedByDeviceSide()
{
base.MeasurementChannelAbstractMethodUsedByDeviceSide();
}
public new void ChannelAbstractMethodUsedByDeviceSide()
{
base.ChannelAbstractMethodUsedByDeviceSide();
}
}
public class HostMeasurementChannel : MeasurementChannelAbstract
{
public new void MeasurementChannelAbstractMethodUsedByHostSide()
{
base.MeasurementChannelAbstractMethodUsedByHostSide();
}
public new void ChannelAbstractMethodUsedByHostSide()
{
base.ChannelAbstractMethodUsedByHostSide();
}
}
现在,DeviceMeasurementChannel
仅使用MeasurementChannelAbstract
设备端的功能。通过声明MeasurementChannelAbstract protected
的所有方法/成员,您必须使用new
关键字才能从外部访问该功能。
这是否可以接受,或者在使用代码后会出现任何陷阱,警告等?
答案 0 :(得分:7)
您可以使用继承解决问题,如下所示:
public abstract class MeasurementChannelAbstract
{
protected abstract void Method();
}
public class DeviceMeasurementChannel : MeasurementChannelAbstract
{
public void Method()
{
// Device side implementation here.
}
}
public class HostMeasurementChannel : MeasurementChannelAbstract
{
public void Method()
{
// Host side implementation here.
}
}
...或通过组合,使用策略模式,如下所示:
public class MeasurementChannel
{
private MeasurementStrategyAbstract m_strategy;
public MeasurementChannel(MeasurementStrategyAbstract strategy)
{
m_strategy = strategy;
}
protected void Method()
{
m_strategy.Measure();
}
}
public abstract class MeasurementStrategyAbstract
{
protected abstract void Measure();
}
public class DeviceMeasurementStrategy : MeasurementStrategyAbstract
{
public void Measure()
{
// Device side implementation here.
}
}
public class HostMeasurementStrategy : MeasurementStrategyAbstract
{
public void Measure()
{
// Host side implementation here.
}
}
在我看来,您希望将继承层次划分为两个标准/测量渠道和设备/主机渠道。一种方法是使用多重继承 - 但C#不支持多重继承(接口除外),并且在大多数情况下,基于组合的设计将更简单。
答案 1 :(得分:5)
对我来说,这看起来有点像你在混淆遗产和构图。当继承的功能没有明显重叠时,你必须“空白”/抛出异常,你的继承图缺少一些中间类。通常这是因为某些功能应该来自其他类的成员实例而不是继承。
考虑实用性,将所有内容映射到完美的OOP不是目标,目标是一个可维护的工作程序,没有巨大的痛苦。
答案 2 :(得分:2)
Rich喜欢暗示:只需要在其中一个具体实现中使用MeasurementChannelAbstract声明的其中一个成员非常清楚地表明您的界面定义不正确,因为它有多个职责。这意味着您的代码(和读者)的客户很难理解抽象并看到各种具体实现之间的差异。
这被称为"Single Responsibility Principle",对于良好的OO设计来说,它是一个重要的。
(有关优秀OO设计的更多信息,我建议您完成所有SOLID原则。)
答案 3 :(得分:0)
听起来好像你还没有完成识别哪些代码共享。将所有通用/共享内容保留在MeasurementChannelAbstract中而不是使用双方调用的不同方法是不是更有意义?我原以为那些应该是继承的课程?
答案 4 :(得分:0)
因此我问自己是否可以 有一个单一的继承链 (接受一些课程会有 主机和设备的功能 (并且)分离成 最后阶段的主机/设备通道 (消除功能 不需要)
我认为没关系。但是,您可以通过为SimpleChannel和MeasurementChannel使用不同的接口来消除不需要的功能。