与相关课程紧密耦合?

时间:2010-12-12 06:49:10

标签: c# .net oop design-patterns

我有定制的向导系统,到目前为止一直很合适。对于大多数向导,页面可以以相当通用的方式构造,因此只有一个类实现这些类型的页面。但是,有些需要自定义设计,因此这些类型的页面有一个抽象基类。由于VS设计器存在一些缺陷,页面本身不能是UI控件,也不是具有通用参数的抽象类(存在用于流畅编程的那些)。因此,我遵循的一个选项是跨两个类实现页面,一个用于UI(源自UserControl并且可以设计),一个用于页面。该页面包含UI控件的一个实例,并将其嵌入其中以供显示。不是最佳的,但它确实有效。

现在,这个设置出现了一个问题:UI控件类和页面类之间存在紧密耦合。这通常不会是一个大问题,除了可以从页面创建页面的专用版本。因此派生的控件和页面类也与自己紧密耦合。因此,当控件和页面类的成员变量,属性和方法分别为控件或页面类型键入时(即,控件类将具有指向页面的属性Page,控件是嵌入式中,我们遇到派生类的一个大问题。每个派生类必须以某种方式更改这些成员的类型。我想到的是包括一个泛型类型参数,允许这些成员通常输入:

public class BaseControl<TControl, TPage>
    where TPage : BasePage<TPage, TControl>
    where TControl : BaseControl<TControl, TPage> {
    public TPage Page { get { ... } set { ... } }
    ...
}

public class BasePage<TPage, TControl>
    where TPage : BasePage<TPage, TControl>
    where TControl : BaseControl<TControl, TPage> {
    public TControl Control { get { ... } set { ... }
    ...
}

public class DerivedControl<TControl, TPage> : BaseControl<TControl, TPage>
    where TControl : DerivedControl<TControl, TPage>
    where TPage : DerivedPage<TPage, TControl> { }

public class DerivedPage<TPage, TControl> : BasePage<TPage, TControl>
    where TControl : DerivedControl<TControl, TPage>
    where TPage : DerivedPage<TPage, TControl> { }

显然,这是我想要避免的那种C ++风格的垃圾。除了丑陋之外,它还会产生一个实际问题,其中必须创建密封的“叶子”类来解决CRTP给我们带来的无限递归问题。

然而替代方案也没有吸引力。我可以让那些成员具有固定类型的基本类型并在任何地方进行投射。这不会强制类型安全,它需要无意义的强制转换(我已经知道类型将是这样的,但编译器不会这样)。我可以把它吸收并将页面和控件类合并为一个,没有abstract或泛型类型参数。这会破坏流畅的编程系统,或者实现起来更加困难,需要多次重复(如果需要我会解释,但我们只是假设 我设计的一部分是合法的)。

因此,对于如何以理智的方式做到这一点,我有点不知所措。我到目前为止所考虑的一切都可以使用,但代码味道很糟糕。有什么我想念的东西,到目前为止我还没有这样做过吗?

1 个答案:

答案 0 :(得分:3)

我在my Protocol Buffers port中有非常类似的代码,其中消息类型和该消息类型的构建器是耦合的。

基本上,你试图表达一种C#泛型让人尴尬的关系。

在我的情况下,大部分都隐藏在生成的代码中,因此开发人员实际上不需要做太多......但它仍然很难看。我确实在寻找替代品,但我没有找到任何替代品。我认为你得到的东西可能会得到你能得到的好,我害怕......假设你写的关于VS约束的内容和你的其他要求是正确的。如果你发现自己能够在一个非常不同的设计中工作,这很棒 - 但如果你需要两种相关的类型,我认为所有这些“垃圾”都是必需的:(