簡體   English   中英

接口如何實現多重繼承

[英]How interfaces achieve multiple inheritance

在許多書中都寫到接口是多重繼承的替代,但我發現它們之間沒有任何相似之處。

繼承對於代碼和功能的可重用性來說非常重要,並且多繼承有助於重用來自多個類的代碼,但是在接口中我沒有找到任何這樣的功能,除了類可以從多個接口繼承。

接口只是函數/方法的聲明,它本身不包含任何實現部分,因此繼承此接口的類應該編寫自己的實現代碼。

所以我覺得在接口的情況下代碼沒有任何可重用性。

是否有任何文件或鏈接可以解答我的疑問與你的回答請分享。

關於代碼的可重用性,你是對的。 在這方面,多個接口不能替代多重繼承。

然而,繼承的另一個方面是:它在基類和子類之間建立了一個is-a關系。 因此,繼承多個超類的類可以充當其中任何一個。 在這方面,接口充當有效的替代,例如,接受接口的方法也將接受實現該接口的任何類,方法與接受從所關注的類派生的任何類的方式相同。 但正如您所說,每個類都必須自己實現接口方法。

例:

public interface Foo {
    int doFoo();
}

public interface Bar {
    long doBar();
}

public class Baz {
    String doBaz() {
        return "This is baz";
    }
}

public class FooBar extends Baz implements Foo, Bar {
    public long doBar() {
        return 123;
    }
    public int doFoo() {
        return 456;
    }
}

// Accepts interface Bar implementing objects
public void doSomething(Bar b) {
    System.out.println(b.doBar() * 10);
}

// Accepts interface Foo implementing objects
public void doSomethingOther(Foo f) {
    System.out.println(f.doFoo() / 10);
}

// Accepts objects of class Baz and subclasses
public void doMore(Baz b) {
    System.out.println(b.doBaz());
}

void bla() {
    FooBar fb = new FooBar();

    // FooBar can act as Foo, Bar, and Baz
    doSomething(fb);
    doSomethingOther(fb);
    doMore(fb);
}

你是對的。

人們的意思是C#中的類型可以實現多個接口。 這與經典繼承不同。

允許你在不同的語境中使用一個類,當然任何類從這樣的類繼承就可以使用基類實現再利用。

請參閱此示例。

 /*interface 1 with two methods*/
    interface IA1
    {
        void Foo1();
        void Foo2();
    }   
   /*Interface two with two methods */
    interface IA2
    {
        void Foo1();
        void Foo3();
    }   



 /*class implemeting two interfaces now. Here class cannot inherit two classes but can inherit two interfcaes.*/
  /* Case1 */
    class CA : IA1, IA2  
    { 
        void IA1.Foo1()//Explicitly Implemented
        {
            Console.WriteLine("In IA1.Foo1");
        }
        void IA2.Foo1() //Explicitly Implemented
        {
            Console.WriteLine("In IA2.Foo1");
        }
        public void Foo2()  //Implicitly Implemented
        {
            Console.WriteLine("In IA1.Foo2");
        }
        public void Foo3()  //Implicitly Implemented
        {
            Console.WriteLine("In IA2.Foo3");
        }
    }


 /* Case2*/
    class CA : IA1, IA2   {
        public void Foo1() //Implicitly Implemented
        {
            Console.WriteLine("In Foo1");
        }
        public void Foo2()  //Implicitly Implemented
        {
            Console.WriteLine("In Foo2");
        }
        public void Foo3()  //Implicitly Implemented
        {
            Console.WriteLine("In Foo3");
        }
    }   

使用接口的概念,類可以繼承一個或多個接口。 並且可以為繼承的接口實現自己的功能。

 Inheritance is mostly important for re-usability of code and functionality 
 and multiple inheritance was helping to re-use code from more than one class, 
 but in Interface I didn't find any such feature except that a class can inherit 
 from more than one interface.

確實,接口提升了代碼的可重用性(特別是與多態性相結合,繼承可以創造奇跡!)。 我可以說出接口可能有益的另一種情況:回調。

由於我們在C#中有代理,我懷疑是否有任何C#開發人員將使用接口作為回調媒介(可能是使用C#1.0的C#開發人員)。 但是對於Java開發人員來說,他們如何在沒有代理的情況下實現回調? 答案:接口。

使用委托進行回調

public delegate int Transformer (int x);

class Util
{
    public static void Transform (int[] values, Transformer t)
    {
        for (int i = 0; i < values.Length; i++)
            values[i] = t (values[i]);
    }
}

class Test
{
    static void Main()
    {
        int[] values = { 1, 2, 3 };
        Util.Transform (values, Square);
        foreach (int i in values)
            Console.Write (i + " "); 
    }

    static int Square (int x) { return x * x; }
}

使用接口回調

public interface ITransformer
{
    int Transform (int x);
}

public class Util
{
    public static void TransformAll (int[] values, ITransformer t)
    {
        for (int i = 0; i < values.Length; i++)
            values[i] = t.Transform (values[i]);
    }
}

class Squarer : ITransformer
{
    public int Transform (int x) { return x * x; }
}

static void Main()
{
    int[] values = { 1, 2, 3 };
    Util.TransformAll (values, new Squarer());
    foreach (int i in values)
         Console.WriteLine (i);
}

有關回調的更多信息,請參閱使用接口和代理的C#回調,使用Java實現回調例程

注意:本文中的示例代碼取自Nutshell中的C#4.0一書(這也是一個很好的C#參考)。

知名開發人員警告我們繼承的危險:
Allen Holub 為何延伸是邪惡
OOP好的部分:消息傳遞,鴨子打字,對象組成,而不是 Nick Fitzgerald的繼承
七個致命的編程罪 - 罪#2: Eric Gunnerson 對繼承過度使用

繼承結合了兩個有些正交的概念:

  1. 派生類可以隱式使用父類的方法和字段來處理與父類匹配的行為部分。
  2. 派生類的對象幾乎可以用於父類的任何對象。

允許類隱式使用來自多個父類的方法和字段會導致一些棘手的問題,例如,如果類X提供抽象方法foo(),則類Y和Z都繼承X並提供foo()的不同實現,並且類Q嘗試繼承Y和Z.如果將類Q的對象o傳遞給期望X的方法(合法的,因為可以使用派生類的對象來使用父類的對象),應該怎樣如果該方法嘗試調用o.foo()會發生什么?

接口通常不存在這樣的問題。 如果接口IY和IZ繼承自包含foo()的接口IX,並且接口IQ繼承了這兩個接口,則實現IQ的類必須提供IQ.foo()的實現,該實現也將用於IY.foo(), IZ.foo()和IX.foo()。 可能會創建模糊的情況,但這些會導致編譯時發出尖叫聲。

實際上,除了C#之外我沒有其他好的答案,Java沒有多重繼承,它應該有。 接口應該能夠取代多重繼承的要點就像是重復足夠多次成為現實的大謊言。

爭論是多重繼承導致了所有這些問題,但我一直聽到C#這些從未使用過C ++的Java開發人員的論點。 我也不記得C ++程序員說“哎呀,我喜歡C ++,但如果他們只能擺脫多重繼承,它就會變成一種很棒的語言”。 人們在實際時使用它而不是在實際時使用它。

您的問題是多重繼承適用的經典案例。 任何重構代碼的建議都告訴你如何解決C#,Java沒有多重繼承的問題。

所有關於“哦,代表團更好,拉迪達”的討論都讓宗教與設計混淆。 沒有正確的方法。 事情要么更有用,要么不那么有用。

在您的情況下,多重繼承將更有用,更優雅的解決方案。

至於重構你的代碼到一個不太有用的形式,以滿足所有從未使用過多重繼承並且相信“多重繼承是壞的”的宗教人士,我想你將不得不降級你的代碼,因為我沒有看到C#,Java任何時候都會以這種方式“改善”。 有太多人重復宗教咒語到愚蠢的程度,我無法看到它被添加到語言中。

......但正如您從上面提供的解決方案中可以看到的那樣,大多數人認為這樣的解決方案將是復雜和混亂的方式!

我寧願自己冒險進入“x extends a,b”領域,即使它是一個非常可怕的解決方案,可能會壓倒大多數C#,Java程序員的能力。

上面建議的解決方案更令人驚訝的是,這里的每個人都建議你將代碼重構為“委托”,因為多重繼承很糟糕,如果他們遇到同樣的問題,就會通過簡單的方法解決問題:“x擴展a,b”並完成它,所有關於“委托與繼承”的宗教論點都將消失。 整個辯論都是愚蠢的,只有無知的程序員才會提出,他們只能證明他們能夠從書中背誦出來的程度以及他們對自己的思考能力如何。

你是100%正確的多重繼承會有所幫助,不,如果你認為C#,Java應該擁有它,你在代碼中做錯了什么。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM