实现接口的抽象基类 [英] Abstract base classes that implement an interface

查看:106
本文介绍了实现接口的抽象基类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我们说,我有一个抽象基类简单的东西像

 抽象类项目:IDisplayable
    {
        公众诠释标识{搞定;组; }
        公共字符串名称{;组; }
        公共抽象无效打印();    }

和我有从继承像

一类

 类主持人:项目
 {
    公众诠释NumberOfLegs {获取;集;}    公共无效打印()
    {
     Console.WriteLine(这是一个简单的接口实现);
    }
 }接口IDisplayable
{
无效打印();
}

子类中没有明确说,这也实现了接口,但它会通过简单的继承这样做。如果我们明确地将接口添加到子类程序将运行相同的(至少据我可以在我简单的例子告诉)。需要显式实现该接口是一个好或坏主意,或者是严格preference的问题?


解决方案

  

如果我们明确的接口添加到子类的程序将运行相同的(至少据我可以在我简单的例子告诉)。


程序不一定会运行相同的;的实例是不足以说明的差别。


  

会明确地实现接口是好还是坏主意,或者是严格preference的问题?


这是一个坏主意,除非你打算确保的接口重新实现语义

让我说明简要介绍。这是什么程序呢?

 使用系统;
接口的IFoo {无效酒吧();巴兹无效(); }
阿尔法类:IFoo的
{
    无效IFoo.Bar()
    {
        Console.WriteLine(Alpha.Bar);
    }
    无效IFoo.Baz()
    {
        Console.WriteLine(Alpha.Baz);
    }
}
布拉沃类:阿尔法
{
    公共无效巴兹()
    {
        Console.WriteLine(Bravo.Baz);
    }
}
类CharlieOne:布拉沃
{
    公共无效酒吧()
    {
        Console.WriteLine(CharlieOne.Bar);
    }
}
类CharlieTwo:布拉沃,IFoo的
{
    公共无效酒吧()
    {
        Console.WriteLine(CharlieTwo.Bar);
    }
}
类节目
{
    静态无效的主要()
    {
        IFoo的富=新的Alpha();
        foo.Bar();
        foo.Baz();
        富=新布拉沃();
        foo.Bar();
        foo.Baz();
        富=新CharlieOne();
        foo.Bar();
        foo.Baz();
        富=新CharlieTwo();
        foo.Bar();
        foo.Baz();
     }
}

在你读,严重:尝试predict这个程序的输出

现在实际运行它。 你得到你所期望的输出?在哪里你的直觉错了?

你看 CharlieOne 之间的差异, CharlieTwo 现在呢? 重新实现的IFoo CharlieTwo 可能会导致接口绑定拿起布拉沃.Baz 即使布拉沃做的的重新实施的IFoo

而在另一方面:如果你希望 Bravo.Baz 被分配到仅仅因为它的存在的接口插槽,那么你怎么看的没有重新实现一个接口,使code是不正确的。对于 Bravo.Baz 来代替 Alpha.IFoo.Baz 布拉沃必须重新实现的IFoo

这里的外卖是:当你重新实现一个接口,的所有的接口绑定重新计算从头开始的 这可能会导致语义改变你的程序,所以只有当你的意思做重新实现一个接口,这样

这也说明了的脆基类故障的的另一种形式。假设布拉沃没有办法巴兹当你写查理 。如果你写查理来重新实现的IFoo 然后布拉沃的作者添加巴兹之后的 - 也许布拉沃的作者是在不同的团队为您的公司 - 更改查理即使这是不是布拉沃的作者预期内的接口绑定。

有关详细信息,请参阅我关于这个问题的文章:

<一个href=\"http://blogs.msdn.com/b/ericlippert/archive/2011/12/08/so-many-interfaces-part-two.aspx\">http://blogs.msdn.com/b/ericlippert/archive/2011/12/08/so-many-interfaces-part-two.aspx

Let's say that I have an abstract base class something simple like

abstract class Item : IDisplayable
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public abstract void Print();

    }

and I have a class that inherits from that like

  class Chair: Item
 {
    public int NumberOfLegs {get;set;}

    public void Print()
    {
     Console.WriteLine("Here is a simple interface implementation");
    }
 }

interface IDisplayable
{
void Print();
}

the child class does not explicitly say that it also implements the Interface, and yet it will do so through simple inheritance. If we explicitly add the Interface to the child classes the program will run the same (at least as far as I can tell in my simple examples). Would explicitly implementing the interface be a good or bad idea, or is it strictly a matter of preference?

解决方案

If we explicitly add the Interface to the child classes the program will run the same (at least as far as I can tell in my simple examples).

The program will not necessarily run the same; your examples are insufficient to illustrate the difference.

Would explicitly implementing the interface be a good or bad idea, or is it strictly a matter of preference?

It is a bad idea unless you intend to ensure interface re-implementation semantics.

Let me illustrate briefly. What does this program do?

using System;
interface IFoo { void Bar(); void Baz(); }
class Alpha : IFoo
{ 
    void IFoo.Bar() 
    {
        Console.WriteLine("Alpha.Bar");
    }
    void IFoo.Baz()
    {
        Console.WriteLine("Alpha.Baz");
    }
}
class Bravo : Alpha
{
    public void Baz()
    {
        Console.WriteLine("Bravo.Baz");
    }
}
class CharlieOne : Bravo
{
    public void Bar() 
    {
        Console.WriteLine("CharlieOne.Bar");
    }
}
class CharlieTwo : Bravo, IFoo
{
    public void Bar() 
    {
        Console.WriteLine("CharlieTwo.Bar");
    }
} 
class Program
{
    static void Main()
    {
        IFoo foo = new Alpha();
        foo.Bar();
        foo.Baz();
        foo = new Bravo();
        foo.Bar();
        foo.Baz();
        foo = new CharlieOne();
        foo.Bar();
        foo.Baz();
        foo = new CharlieTwo();
        foo.Bar();
        foo.Baz();
     }
}

Before you read on, seriously: try to predict the output of this program.

Now actually run it. Did you get the output you expected? Where was your intuition wrong?

Do you see the difference between CharlieOne and CharlieTwo now? Re-implementing IFoo in CharlieTwo can cause the interface binding to pick up Bravo.Baz even though Bravo does not re-implement IFoo!

And on the other hand: if you expected Bravo.Baz to be assigned to the interface slot just because it exists, then you see how failing to re-implement an interface causes the code to be incorrect. For Bravo.Baz to replace Alpha.IFoo.Baz, Bravo must re-implement IFoo.

The takeaway here is: when you re-implement an interface, all the interface bindings are recomputed from scratch. This can cause semantic changes in your program, so only re-implement an interface when you mean to do so.

This also illustrates yet another form of the brittle base class failure. Suppose Bravo does not have method Baz when you write Charlie. If you write Charlie to re-implement IFoo then the author of Bravo adding Baz afterwards -- perhaps the authors of Bravo are on a different team at your company -- changes the interface bindings within Charlie even if that is not what the authors of Bravo intended.

For more information, see my article on the subject:

http://blogs.msdn.com/b/ericlippert/archive/2011/12/08/so-many-interfaces-part-two.aspx

这篇关于实现接口的抽象基类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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