代码之家  ›  专栏  ›  技术社区  ›  Mizipzor

要使用的设计模式,而不是多重继承

  •  23
  • Mizipzor  · 技术社区  · 14 年前

    来自C++背景,用于多重继承。我喜欢一把猎枪对准我脚的感觉。现在,我在C语言和Java中工作得更多,在这里你只能继承一个基础类,但实现了任意数量的接口(我得到的术语是正确的吗?).

    例如,让我们考虑两个实现公共接口但不同(但却是必需的)基类的类:

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

    两个班都是 UserControl 所以我不能代替基类。两者都需要实现 DoMagic 功能。我现在的问题是函数的两个实现是相同的。我讨厌复制粘贴代码。

    (可能的)解决方案:

    1. 我当然想 TypeA TypeB 共享一个公共基类,在这里我可以只编写一次相同的函数定义。但是,由于只有一个基类的限制,我无法在层次结构中找到适合它的位置。
    2. 也可以尝试实现一种 composite pattern . 放 多马的 函数在一个单独的helper类中,但是这里的函数需要(和修改)相当多的内部变量/字段。将它们全部作为(引用)参数发送看起来很糟糕。
    3. 我的直觉告诉我 adapter pattern 在这里可以有一个位置,一些类在必要时在两者之间转换。但这也让人觉得有点老套。

    我将其标记为语言不可知,因为它适用于所有使用这种单基类多接口方法的语言。

    另外,请指出我是否误解了我命名的任何模式。

    在C++中,我只使用私有字段、函数实现来创建一个类,并将其放入继承列表中。C/Java等中的正确方法是什么?

    8 回复  |  直到 14 年前
        1
  •  10
  •   Dinah SLaks    14 年前

    你可以使用策略模式或类似的方法 有一个 (组成)而不是 是一个 (继承权):

    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成员(例如通过构造函数将其作为param传递),但以上方法应该可以帮助您开始。

        2
  •  9
  •   Patrick Karcher    14 年前
    • 在.NET中,可以将扩展方法应用于接口。如果可能的话,它真的很整洁,而且适用于你,因为这是一种很少见的应用 实施 到一个接口。当然可以考虑一下,但你这么说可能对你不起作用 DoMagic 与很多私人成员合作。你能把这些私有变量打包吗 internal 可能吗?这样扩展方法就可以访问它们。
    • 在另一个类中具有公共功能。如果有一个逻辑位置放置这个公共功能,请将对象传递给另一个类方法(可能这是ui功能,并且您已经有了ui助手)。..)同样,您能用内部/公共属性公开私有数据吗?(安全性/封装当然是所有这一切的一个关注点。我不知道您的类是仅供内部使用还是将公开发布。)
    • 否则,请将单独的功能类(或特定的函数指针)传递到接口定义的方法中。要将私有变量传递给这个外部函数引用,您必须有一点重复的代码,但至少不会太多,而且您的实现将在一个地方。
    • 我们可能把事情弄得太复杂了。当你今晚睡觉的时候,它不会让你感觉到所有的面向对象,但是你能在你的库中有一个所有imagician实现者调用的静态例程吗?
    • 最后,适配器可能确实是您要找的。可能性较小但仍值得考虑的是 Decorator pattern .

    如果没有什么特别好的,选择感觉最好的, 用它 几次,明天重新安排。:)

        3
  •  3
  •   Roman    14 年前

    用组合替换继承。

    将“common”函数移动到单独的类,创建该类的实例,并将其插入typea对象和typeb对象。

        4
  •  3
  •   Justin Niessner    14 年前

    你的直觉在这种情况下是正确的。适配器模式是您正在寻找的。

    DoFaCoto有好的.NET示例(也应该与Java的同行非常接近):

    Adapter Design Pattern in C# and VB.NET

        5
  •  1
  •   Björn Pollex    14 年前

    复合模式是针对复杂对象的,这意味着焦点是由其他对象组成的一个对象。这个 strategy-pattern 可以看作是一个特例,但战略不一定是一个对象。我认为这更适用于你的案子。再说一遍,这在很大程度上取决于 DoMagic() 做。

        6
  •  1
  •   Virgil    14 年前
    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—这里不需要任何实现]

        7
  •  0
  •   Dinah SLaks    14 年前

    你可以使用构图把魔术师作为类型A和类型B的属性

    class Magician : IMagician
    {
        public void DoMagic()
        {}
    }
    
    Class TypeA : CustomButtonUserControl
    {
       //property
       Magician magicianInTypeA
    }
    
    Class TypeB : CustomTextUserControl
    {
        //property
        Magician magicianInTypeB
    }
    
        8
  •  -3
  •   Itay Moav -Malimovka    14 年前
    abstract class Magical: CustomButtonUserControl
    {
        public void DoMagic()
        {
            // ...
        }
    }
    
    public class TypeA : Magical
    {
    
    }
    
    public class TypeB : Magical
    {
    
    }