2012-05-27 19 views
5

Tengo una pregunta teórica sobre cómo tratar el siguiente escenario en un lenguaje que no permite herencia múltiple.Herencia múltiple sin herencia múltiple y sin duplicación de código

imaginar que tienen una clase base Foo y desde que estoy deseando crear tres subclases:

  • Clase Bar hereda Foo e implementa la funcionalidad "A"
  • Clase Baz hereda Foo e implementa la funcionalidad "B"
  • Clase Qux hereda Foo e implementa funcionalidades "A" y "B"

imaginar que el código para implementar funcionalidades "A" y "B" es siempre la misma. ¿Hay alguna manera de escribir el código para "A" y "B" solo una vez y luego aplicar las clases apropiadas (o "heredarlo")?

+0

¿Algún idioma en particular? ¿Java? DO#? ¿Algo más? – Tudor

+0

¿Por qué no estás implementando la misma funcionalidad dentro de tu clase FOO, y solo marcas A/B como virtual/sobresatible? – YavgenyP

+0

@Tudor Estaba pensando en C#, pero cualquier lenguaje OOP que no permite herencia múltiple está bien. –

Respuesta

3

Bueno, la única manera que puedo verte lograr esto en C#/Java es por la composición. Considere esto:

class Foo { 

} 

interface A { 
    public void a(); 
} 

interface B { 
    public void b(); 
} 

class ImplA implements A { 
    @Override 
    public void a() { 
     System.out.println("a"); 
    } 
} 

class ImplB implements B { 
    @Override 
    public void b() { 
     System.out.println("b"); 
    } 
} 

class Bar extends Foo { 
    A a = new ImplA(); 

    public void a() { 
     a.a(); 
    } 
} 

class Baz extends Foo { 
    B b = new ImplB(); 

    public void b() { 
     b.b(); 
    }  
} 

class Qux extends Foo { 

    A a = new ImplA(); 
    B b = new ImplB(); 

    public void b() { 
     b.b(); 
    } 

    public void a() { 
     a.a();   
    }  
} 

Ahora Qux tiene tanto la funcionalidad de Foo través de la herencia normal, sino también las implementaciones de A y B por composición.

1

Esto se puede lograr en los idiomas que proporciona rasgos (aquí: ):

class Foo { 
    def fooM() {} 
} 

trait A { 
    def aFunc() {} 
} 

trait B { 
    def bFunc() {} 
} 

class Bar extends Foo with A {} 

class Baz extends Foo with B {} 

class Qux extends Foo with A with B {} 

Debido Scala se ejecuta en la parte superior de Java (que ni tiene herencia múltiple ni rasgos) que se traduce en algo como esto (simplificado) - lo que podría ser un indicio de cómo implementarlo en Java/C# manualmente:

class Foo { 
} 

interface A { 
    void aFunc(); 
} 

interface B { 
    void bFunc(); 
} 

class Bar extends Foo implements A { 

    public void aFunc() { 
     $A.aFunc(); 
    } 
} 

class Baz extends Foo implements B { 

    public void bFunc() { 
     $B.bFunc(); 
    } 
} 

class Qux extends Foo implements A, B { 

    public void aFunc() { 
     $A.aFunc(); 
    } 

    public void bFunc() { 
     $B.bFunc(); 
    } 
} 

class $A { 

    public static void aFunc() {} 
} 

class $B { 

    public static void bFunc() {} 
} 
3

El término más general para esto es Mixin. Algunos idiomas proporcionan soporte de inmediato, como Scala y D. Sin embargo, existen varias formas de lograr los mismos resultados en otros lenguajes.

Una forma en que puede crear una pseudo-mixina en C# es utilizar interfaces vacías y proporcionar los métodos con métodos de extensión.

interface A { } 
static class AMixin { 
    public static void aFunc(this A inst) { 
     ... //implementation to work for all A. 
    } 
} 

interface B { } 
static class BMixin { 
    public static void bFunc(this B inst) { 
     ... 
    } 
} 

class Qux : Foo, A, B { 
    ... 
} 
1

Existen varias formas de hacer algo como esto. Más específicamente, si abandonamos el aspecto de herencia por un momento, hay formas de introducir la misma unidad de funcionalidad en diferentes clases, mientras escribimos la unidad solo una vez.

Bien, I amorAOP Frameworks, y existen para muchos idiomas (C# y Java tienen varios). AOP Frameworks básicamente le permite agregar funcionalidad autónoma en diferentes clases en toda su estructura de herencia.

Para C#, tiene PostSharp y para Java tiene AspectJ, entre muchos otros.

Muchos marcos AOP permiten llamadas de método 'secuestro' o 'anulación' sin usar herencia.