簡體   English   中英

設計模式使用而不是多重繼承

[英]Design pattern to use instead of multiple inheritance

來自C ++背景,我習慣了多重繼承。 我喜歡瞄准我腳的霰彈槍的感覺。 如今,我在C#和Java中工作得更多,在那里你只能繼承一個基類但實現任意數量的接口(我的術語是否合適?)。

例如,讓我們考慮兩個實現公共接口但不同(但需要)基類的類:

public class TypeA : CustomButtonUserControl, IMagician
{
    public void DoMagic()
    {
        // ...
    }
}

public class TypeB : CustomTextUserControl, IMagician
{
    public void DoMagic()
    {
        // ...
    }
}

這兩個類都是UserControl所以我不能替換基類。 兩者都需要實現DoMagic功能。 我現在的問題是該函數的兩個實現都是相同的。 我討厭復制粘貼代碼。

(可能的)解決方案:

  1. 我自然希望TypeATypeB共享一個公共基類,在那里我只能編寫一次相同的函數定義。 但是,由於只有一個基類的限制,我無法在層次結構中找到適合的位置。
  2. 人們也可以嘗試實現一種復合模式 DoMagic函數放在一個單獨的幫助器類中,但這里的函數需要(並修改)相當多的內部變量/字段。 將它們全部作為(參考)參數發送只會看起來很糟糕。
  3. 我的直覺告訴我, 適配器模式可以在這里有一個位置,一些類在必要時在兩者之間進行轉換。 但它也感覺很hacky。

我用語言無關來標記它,因為它適用於使用這種one-baseclass-many-interfaces方法的所有語言。

另外,請指出我是否誤解了我提到的任何模式。

在C ++中,我只使用私有字段創建一個類,該函數實現並將其放在繼承列表中。 什么是C#/ Java之類的正確方法?

您可以使用策略模式或類似的東西使用具有 (組成),而不是一個 (繼承):

public class TypeA : CustomButtonUserControl, IMagician {
    IMagician magicObj = new Magical();
    public void DoMagic() {
        magicObj.DoMagic();
    }
}

public class TypeB : CustomButtonUserControl, IMagician {
    IMagician magicObj = new Magical();
    public void DoMagic() {
        magicObj.DoMagic();
    }
}

public class Magical : IMagician {
    public void DoMagic() {
        // shared magic
    }
}

還有其他方法來實例化您的私有IMagician成員(例如通過構造函數將它們作為參數傳遞),但上面的內容應該讓您開始。

  • 在.Net中,您可以將擴展方法應用於接口。 在可能的情況下它非常簡潔,適用於您,因為這是將常見實現應用於接口的一種罕見方式。 當然要考慮它,但它可能不適合你,因為你說DoMagic與很多私人成員合作。 你可以在internal打包這些私有變量嗎? 這樣,擴展方法可以訪問它們。
  • 在另一個類中具有通用功能。 如果有一個合理的位置來放置這個常用功能,將對象傳遞給另一個類方法(也許這是UI功能,你已經有了一個UI助手......)。 再次,您可以使用內部/公共屬性公開私有數據嗎? (安全/封裝當然是一個問題。我不知道你的課程是僅供內部使用還是公開展示。)
  • 否則,將單獨的功能類(或特定函數指針)傳遞給接口定義的方法。 你必須有一些重復的代碼將你的私有變量傳遞給這個外部函數引用,但至少它不會太多,你的實現將在一個地方。
  • 我們可能會讓這太復雜了。 當你今晚入睡時,它不會讓你覺得所有面向對象,但是你可以在你的圖書館里有一個所有IMagician實施者所稱的靜態例程嗎?
  • 最后,適配器可能確實是您正在尋找的。 不太可能但仍值得考慮的是Decorator模式

如果沒有顯得特別好,選擇什么樣的感覺最好, 用它幾次,並重新安排明天。 :)

用組合替換繼承。

將'common'函數移動到單獨的類,創建該類的實例,並將其插入TypeA對象和TypeB對象。

在這種情況下,你的直覺是正確的。 適配器模式是您正在尋找的。

DoFactory有很好的.NET示例(它們應該非常接近它們的Java對應物):

C#和VB.NET中的適配器設計模式

復合圖案適用於復雜對象,這意味着焦點在於一個對象由其他對象組成。 策略模式可以被視為一種特殊情況,但策略不一定是一個對象。 我認為這將更適用於您的情況。 然后,這在很大程度上取決於DoMagic()的性質。

public interface  IMagician{ /* declare here all the getter/setter methods that you need; they will be implemented both in TypeA and TypeB, right? */ }

public static class MyExtensions {
  public static void doMagic(this IMagician obj)
  { 
           // do your magic here
  }
}   

現在,問題是如果你真的需要使用私有屬性/方法(而不是“內部”屬性),這種方法將無法工作。 嗯,實際上,如果你能通過反射閱讀這些屬性,你可能能夠發揮你的魔力,但即使它有效,它也是一個相當丑陋的解決方案:)

[請注意,“doMagic”將自動顯示為TypeA和TypeB的一部分,只是因為您實現了IMagician - 沒有必要在那里實現任何實現]

您可以使用合成將魔術師作為typeA和typeB的屬性

class Magician : IMagician
{
    public void DoMagic()
    {}
}

Class TypeA : CustomButtonUserControl
{
   //property
   Magician magicianInTypeA
}

Class TypeB : CustomTextUserControl
{
    //property
    Magician magicianInTypeB
}
abstract class Magical: CustomButtonUserControl
{
    public void DoMagic()
    {
        // ...
    }
}

public class TypeA : Magical
{

}

public class TypeB : Magical
{

}

暫無
暫無

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

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