基类实现基本接口,而派生/混凝土类实现扩展接口,为什么呢? [英] base class implementing base interface while derived/concrete class implementing extended interface, why?

查看:76
本文介绍了基类实现基本接口,而派生/混凝土类实现扩展接口,为什么呢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习一本书,即《使用C#进行.NET域驱动的设计》.

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

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

在此图中,

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

B)IRepository接口也由接口ICompanyRepository(ICompanyRepository : IRepository)扩展.

C)ICompanyRepository由CompanyRepository实现,该CompanyRepository派生自SQLRepositoryBase,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 是否由于"RepositoryBase"实现了IRepoitory而在基类"RepositoryBase"中调用了此Add()函数?(因此,必须强制RepositoryBase类实现IRepository才能调用Add())

OR

机制2:之所以调用基类"RepositoryBase"中的Add()函数,是因为CompanyRepository实现了ICompanyRepository,该公司实现了IRepository,该IRepository包含Add()函数的定义,这样,当调用ICompanyRepository(带有变量ICompanyRepository)时,它首先会找到定义在ICompanyRepository中添加,然后在父接口IRepository中添加,然后跳转到CompanyRepository类以查找Add()函数的实现,而没有找到Add()函数的定义,它向上遍历到父类SQLRepositoryBase以查找Add()函数,依此类推,并在RepositoryBase类中找到函数Add(),因此它将在RepositoryBase中调用Add()函数.这意味着,如果它将在RepositoryBase的任何派生类中找到Add()函数,则它不会进一步向上移动(在父类中).所有这些还意味着,为了在类链中从派生类遍历到父类只是为了找到Add()函数,RepositoryBase类真的不需要直接从IRepository继承吗?


我的问题中还有其他内容,我无法理解,如下所述,我的情况下适用的是OO-Rule:

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

类层次结构链中的最后一个派生类"CompanyRepository"实现ICompanyRepository(CompanyRepository不实现IRepository接口的Add()函数),而根(最高父级)(抽象基类)即RepositoryBase实现Add()函数

因此结构类似于 http://screencast.com/t/a9UULJVW0 中显示的图像

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

code ICompanyRepository lastDerived = new CompanyRepository();ICompanyRepository-> Add(); 代码

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

但是,在我的案例中,CompanyRepository类没有实现IRepository.Add(){},尽管控制流(在跟踪时)成功跳转到了基类中的Add()函数(并且代码运行正常).我不明白哪个OO-Rule在这里适用?

如果您需要我用代码显示以上情况,请告诉我.

解决方案

很多话.我要重申一下我认为您要问的问题,然后回答该问题.如果我没有能力,请告诉我.

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

是的,这称为接口重新实现",它更改了方法的映射方式.C#语言规范(第13.4.6节接口重新实现")对此进行了更详细的介绍,但要点是,指定该接口的最派生类型是查找的起点.

 接口ICreature{无效Speak();}动物:ICreature{公共无效Speak(){Console.WriteLine("Rawr");}}鸭类:动物{公共无效Speak(){Console.WriteLine("Quack");}}人类:动物,自然{公共无效Speak(){Console.WriteLine("Hello");}} 

如果执行以下操作,它将打印出"Rawr"和"Hello".

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

这是因为在Duck层次结构中,指定ICreature接口的最派生类型为Animal,因此它将打印出"Rawr".

在人员层次结构中,指定ICreature接口的最派生类型为人员(人员声明了实现),因此它将打印出"Hello".如果Human类型没有声明实现,那么它还将打印"Rawr".

更新

在您的特定情况下,将应用完全相同的规则.让我们逐步完成这些步骤.

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

然后,调用链将按照以下步骤操作.

  • 通过键入ICompanyRepository接口的实例调用 Add()方法.
  • 明确声明实现了IRepository的最派生类型现在是CompanyRepository,因此查找从此处开始.
  • CompanyRepository不会直接实现Add()方法,因此将检查其父类.
  • 已检查SQLRepositoryBase并没有直接实现该方法,因此要检查其父类.
  • 检查
  • RepositoryBase并实现实现该方法,因此将被调用该方法.

I am following a book namely ".NET Domain Driven Design with C#".

Question is based on scenario as shown in Class Diagram below:

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

In this diagram,

A) IRepository interface is implemented by (abstract base class) RepositoryBase whereas,

B) IRepository interface is also extended by interface ICompanyRepository (ICompanyRepository : IRepository).

C) ICompanyRepository is implemented by CompanyRepository which is derived from SQLRepositoryBase which is derived from RepositoryBase (; which, as stated in point A), implements IRepository which is parent if ICompanyRepository).

D) i create a variable of interface ICompanyRepository having reference to object of clas CompanyRepository, like below:

ICompanyRepository comRep = new Company Repository();

Now, if i call Add() function with ICompanyRepository variable comRep...

comRep.Add(); 

then Add() function in RepositoryBase class (which is parent of CompanyRepository) is called.

My Question: What is the exact underlying Object Oriented Rule/Mechanism takes place due to which the function Add() in (abstract-base) class "RepositoryBase" is called? For convenience i am stating below two possible mechanisms: (please tell me which one of two stated below is correct underlying mechanism)

Mechanism-1 Is this Add() function in base class "RepositoryBase" is called because "RepositoryBase" implements IRepoitory ? (Hence making it mandatory for RepositoryBase class to implement IRepository in order to call Add() )

OR

Mechanism-2: The Add() function in base class "RepositoryBase" is called because CompanyRepository implements ICompanyRepository which implements IRepository which contains definition for Add() function such that when Add() function is called on (with variable of) ICompanyRepository then it first finds the definition of Add in ICompanyRepository and then in parent interface IRepository and then jumps to CompanyRepository class to find implementation of Add() function and not finding the definition of Add() function it traverse upward to parent class SQLRepositoryBase to find Add() function and so on, and as it finds the function Add() in RepositoryBase class so it calls the Add() function in RepositoryBase. This means that if it would have found the Add() function in any of derived classes of RepositoryBase, it had not traverse further upward (in parent class). All of this also means that , in order to traverse from derived class to parent class in chain of classes just to find Add() function, the RepositoryBase class does not really need to inherit directly from IRepository?


There are additional thing in my question and i am unable to understand which OO-Rule is applying in my case as stated below:

In my Question there are two Interfaces one is parent namely IRepository and other is extending it namely ICompanyRepository. Parent interface IRepository contains deifinition of Add() function but not the child interface ICopmanyRepository.

Last derived class in the chain of class Hierarchy "CompanyRepository" implements ICompanyRepository (CompanyRepository does not implement Add() function of IRepository interface) whereas root (top most parent) (abstract base) class namely RepositoryBase implements the Add() function.

So the structure is like the image shown in http://screencast.com/t/a9UULJVW0.

Now if i call Add() function:

codeICompanyRepository lastDerived = new CompanyRepository(); ICompanyRepository->Add();code

Then according to the OO-Rule you stated in you answer, the lookup will start from CompanyRepository class with expectation that CompanyRepository would have implemented Add() function as code IRepository.Add() { } //deduced from P17 and P18 in [link] http://www.codeproject.com/Articles/18743/Interfaces-in-C-For-Beginners[link]code

BUT, in my case class CompanyRepository does not have implementation IRepository.Add() { } although the flow of control (while tracing) jumps to Add() function in base class successfully (And code is working fine). I am unable to understand which OO-Rule is applying here ?

Please let me know if you need me to show above scenario with code.

解决方案

That's a lot of words. I'm going to restate what I think you're asking and answer that question instead. If I'm off the mark, let me know.

When invoking a method through an interface, does it matter if that interface is explicitly declared again as being implemented on a more derived type in the type hierarchy?

Yes, this is called "interface re-implementation" and it changes how the method is mapped. The C# language specification (Section 13.4.6 Interface Re-Implementation) goes into this in a little bit more detail, but the gist is that the most derived type that specifies that interface is the starting point for lookup.

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"); }
}

If you do the following, it will print out "Rawr" and "Hello".

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

This is because in the Duck hierarchy, the most derived type specifying the ICreature interface is Animal and so it will print out "Rawr".

In the Human hierarchy, the most derived type specifying the ICreature interface is Human (and Human declares an implementation) and so it will print out "Hello". If the Human type had not declared an implementation, it would also have printed "Rawr".

Update

In your specific case, the exact same rule applies. Let's walk through the steps.

  • ICompanyRepository inherits from IRepository
  • CompanyRepository declares that it implements ICompanyRepository
  • CompanyRepository has now implicitly redeclared that it implements IRepository because ICompanyRepository inherits from IRepository

The call chain then follows these steps.

  • The Add() method is called through the instance typed to the ICompanyRepository interface.
  • The most derived type that has explicitly declared that it implements IRepository is now CompanyRepository, so lookup begins there.
  • CompanyRepository does not implement the Add() method directly, so its parent class is inspected.
  • SQLRepositoryBase is inspected and does not directly implement the method, so its parent class is inspected.
  • RepositoryBase is inspected and it does implement the method, so that is the method that will be called.

这篇关于基类实现基本接口,而派生/混凝土类实现扩展接口,为什么呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆