继承问题 - 声明相同属性的抽象和具体版本

时间:2009-08-08 00:19:26

标签: c# oop

好的,有两种选择,但在我开始之前,你需要知道这一点:

public abstract class GatewayBase { ... }

public class Gateway : GatewayBase { ... }

备选方案#1

public abstract class ModelBase
{
    public GatewayBase GatewayBase { get; private set; } // property named GatewayBase

    public ModelBase(GatewayBase gateway)
    {
        GatewayBase = gateway;
    }
}

public class Model : ModelBase
{
    public Gateway Gateway { get; private set; } // property named Gateway

    public Model(Gateway gateway)
        : base(gateway)
    {
        Gateway = gateway;
    }
}

备选方案#2

public abstract class ModelBase
{
    public GatewayBase Gateway { get; private set; } // property named Gateway

    public ModelBase(GatewayBase gateway)
    {
        Gateway = gateway;
    }
}

public class Model : ModelBase
{
    public new Gateway Gateway { get; private set; } // property named Gateway plus "new" modifier

    public Model(Gateway gateway)
        : base(gateway)
    {
        Gateway = gateway;
    }
}

讨论:

使用备选方案#1,具体类Model可以“看到”两个版本的Gateway。一个称为GatewayBase,另一个称为Gateway,但它们都包含完全相同的实例。对于备选方案#2,从技术上讲,仍有两个版本Gateway,但有一个隐藏另一个版本,因此实际上只有一个版本(除非您使用base.Gateway绕过它)。我喜欢替代#2让我可以在任何地方调用属性Gateway,因为它在基础类和具体类中都得到了很多使用,而且它是一个简短但清晰的名称。不过,我对以这种方式使用new修饰符犹豫不决。这真的是隐藏房产的合法方案吗?

您会选择哪个以及为什么?

或者随意提出其他选择。

感谢。

修改

我应该提到GatewayBaseModelBase位于依赖程序集中,因此他们对GatewayModel一无所知。但是,GatewayModel当然知道GatewayBaseModelBase

2 个答案:

答案 0 :(得分:2)

选项2看起来更干净,但不要创建单独的支持属性,将现有的基类'属性从GatewayBase强制转换为Gateway。通过这种方式,您不会对使用的网关产生歧义:它总是相同的,只是从不同的角度来看:

public abstract class ModelBase
{
    public ModelBase(GatewayBase gateway)
    {
        this.Gateway = gateway;
    }

    public GatewayBase Gateway { get; private set; }
}

public class Model : ModelBase
{
    public Model(Gateway gateway)
        : base(gateway)
    {
    }

    public new Gateway { get { return (Gateway) base.Gateway; } }
}

您还可以使用泛型来为不同类型的网关保持一点灵活性(有点像IEnumerable< T>)。泛型的问题在于你不能施放一个C< X>。另一个C< Y> (好吧,有时你可以在4.0)。解决这个问题的最简单方法是引入一个非泛型接口,您可以在泛型类上显式实现。这样,当您与通用实例交谈时,它就会隐藏起来,但您仍然可以混合使用C< X>和C< Y&gt ;.

public interface IModel
{
    GatewayBase Gateway { get; }
}

public abstract class ModelBase<TGateway> : IModel
    where T : GatewayBase
{
    public ModelBase(TGateway gateway)
    {
        this.Gateway = gateway;
    }

    public TGateway Gateway { get; private set; }

    GatewayBase IModel.Gateway { get { return this.Gateway; } }
}

public class Model : ModelBase<Gateway>
{
    public Model(Gateway gateway)
        : base(gateway)
    {
    }
}

答案 1 :(得分:0)

我不确定你为什么要第二个Gateway属性。 Gateway是否具有与GatewayBase不同的接口?如果是这样,我看到了差异,但一般来说我认为它可能不是最好的设计。我会认真考虑Gateway是否应该公开除GatewayBase之外的任何其他属性/方法。如果没有,那么您不需要Model.Gateway属性。

当两个类之间存在“Is A”关系时,最好只使用继承。这意味着Gateway“Is A”GatewayBase并且通常应该具有相同的属性/方法,至少是公共的。