基类实现基接口而派生/具体类实现扩展接口,为什么?

时间:2013-09-24 19:19:18

标签: c# oop inheritance interface interface-implementation

我正在阅读一本书“使用C#进行.NET域驱动设计”。

问题基于以下类图所示的场景:

图: http://screencast.com/t/a9UULJVW0

在此图中,

A)IRepository接口由(抽象基类)RepositoryBase实现,而

B)IRepository接口也由接口ICompanyRepository(ICompanyRepository IRepository)扩展。

C)ICompanyRepository由CompanyRepository实现,它派生自SQLRepositoryBase,它源自RepositoryBase(;如A点所述),实现IRepository,如果是ICompanyRepository,则为父级。

D)我创建了一个接口ICompanyRepository的变量,它引用了clas CompanyRepository的对象,如下所示:

ICompanyRepository comRep = new Company Repository();

现在,如果我使用ICompanyRepository变量comRep ...

调用Add()函数
comRep.Add(); 

然后调用RepositoryBase类(它是CompanyRepository的父级)中的Add()函数。

我的问题: 由于调用(抽象 - 基础)类“RepositoryBase”中的函数Add()被调用,导致的面向对象的规则/机制是什么?为方便起见,我在下面陈述两种可能的机制:(请告诉我下面两个中哪一个是正确的潜在机制)

机制-1 这个Add()函数是否在基类“RepositoryBase”中被调用,因为“RepositoryBase”实现了IRepoitory? (因此强制RepositoryBase类实现IRepository以调用Add())

OR

机制-2: 调用基类“RepositoryBase”中的Add()函数是因为CompanyRepository实现了ICompanyRepository,它实现了包含Add()函数定义的IRepository,这样当调用Add()函数(带有变量)ICompanyRepository时它首先找到定义在ICompanyRepository中添加然后在父接口IRepository中然后跳转到CompanyRepository类以查找Add()函数的实现而没有找到Add()函数的定义它向上遍历到父类SQLRepositoryBase以查找Add()函数等等,并且它在RepositoryBase类中找到函数Add(),因此它调用RepositoryBase中的Add()函数。这意味着如果它在RepositoryBase的任何派生类中找到Add()函数,它就不会进一步向上遍历(在父类中)。所有这一切也意味着,为了从派生类遍历类链中的父类只是为了找到Add()函数,RepositoryBase类真的不需要直接从IRepository继承吗?


我的问题中还有其他内容,我无法理解在我的案例中适用的OO规则如下所述:

在我的问题中有两个接口,一个是父级,即IRepository,另一个是扩展它,即ICompanyRepository。父接口IRepository包含Add()函数的定义,但不包含子接口ICopmanyRepository。

类层次结构“CompanyRepository”链中的最后派生类实现ICompanyRepository(CompanyRepository不实现IRepository接口的Add()函数)而root(最顶层父)(抽象基类)类即RepositoryBase实现Add()函数

所以结构就像http://screencast.com/t/a9UULJVW0中显示的图像一样。

现在如果我调用Add()函数:

code ICompanyRepository lastDerived = new CompanyRepository(); ICompanyRepository->添加(); code

然后根据您在回答中提到的OO规则,查找将从CompanyRepository类开始,期望CompanyRepository将Add()函数实现为 code IRepository.Add(){ } //从[link] http://www.codeproject.com/Articles/18743/Interfaces-in-C-For-Beginners[link] code

中的P17和P18推导出来

但是,在我的案例类中,CompanyRepository没有实现IRepository.Add(){},尽管控制流(在跟踪时)成功跳转到基类中的Add()函数(并且代码工作正常)。我无法理解哪个OO规则适用于此处?

如果您需要我使用代码显示上述方案,请告诉我。

1 个答案:

答案 0 :(得分:6)

这是很多话。我要重申我认为你在问的问题并改为回答这个问题。如果我不合适,请告诉我。

  

通过接口调用方法时,是否重要   接口显式声明为在更多派生类型上实现   在类型层次结构?

是的,这称为“接口重新实现”,它会更改方法的映射方式。 C#语言规范(第13.4.6节“接口重新实现”)更详细地介绍了这一点,但要点是指定该接口的最派生类型是查找的起始点。

interface ICreature
{
    void Speak();
}

class Animal : ICreature
{
    public void Speak() { Console.WriteLine("Rawr"); }
}

class Duck:Animal
{
    public void Speak() { Console.WriteLine("Quack"); }
}

class Human : Animal, ICreature
{
    public void Speak() { Console.WriteLine("Hello"); }
}

如果您执行以下操作,它将打印出“Rawr”和“Hello”。

ICreature duck = new Duck();
ICreature human = new Human();
duck.Speak();
human.Speak();

这是因为在Duck层次结构中,指定ICreature界面的派生类型最多的是Animal,因此它将打印出“Rawr”。

在Human层次结构中,指定ICreature接口的派生类型最多的是Human(和Human声明实现),因此它将打印出“Hello”。如果Human类型没有声明实现,它也会打印“Rawr”。

更新

在您的具体情况下,适用完全相同的规则。让我们来看看这些步骤。

  • ICompanyRepository继承自IRepository
  • CompanyRepository声明它实现了ICompanyRepository
  • 现在,CompanyRepository已隐式重新声明它实现了IRepository,因为ICompanyRepository继承自IRepository

然后,调用链遵循以下步骤。

  • 通过键入ICompanyRepository接口的实例调用Add()方法。
  • 显式声明它实现IRepository的派生程度最高的类型现在是CompanyRepository,因此从那里开始查找。
  • CompanyRepository不直接实现Add()方法,因此会检查其父类。
  • 检查SQLRepositoryBase并且不直接实现该方法,因此检查其父类。
  • 检查RepositoryBase并且实现该方法,因此这将是要调用的方法。