2008-11-04 12 views
14

¿Hay alguna manera de emular mezclas o rasgos en java? Básicamente, necesito una forma de hacer herencia múltiple, así que puedo agregar lógica empresarial común a varias clasesrasgos java o patrón mixins?

Respuesta

12

Me gustaría encapsular toda la lógica de negocios en una nueva clase BusinessLogic y hacer que cada clase que necesita BusinessLogic haga llamadas a la clase. Si necesita una única jerarquía arraigado para sus clases que hacen llamadas a BusinessLogic, tendrá que crear una interfaz también (BusinessLogicInterface?)

En pseudo-código:

interface BusinessLogicInterace 
{ 
    void method1(); 
    void method2(); 
} 

class BusinessLogic implements BusinessLogicInterface 
{ 
    void method1() { ... } 
    void method2() { ... } 
} 

class User 
    extends OtherClass 
    implements BusinessLogicInterface 
{ 
    BusinessLogic logic = new BusinessLogic(); 

    @Override 
    void method1() { logic.method1(); } 

    @Override 
    void method2() { logic.method2(); } 
} 

Esto no es la implementación más bonita para solucionar la falta de herencia múltiple y se vuelve bastante engorrosa cuando la interfaz tiene muchos métodos. Lo más probable es que quieras intentar rediseñar tu código para evitar necesitar mixins.

+0

bien, entonces no hay trucos para evitar tener que usar la delegación e invocar lógicamente.method1, logic.method2, logic.method3 explícitamente? ayudaría a ahorrar en el tipeo y el código repetitivo. – joshjdevl

+1

@joshjdevl Hay, pero significa [piratear el compilador] (http://projectlombok.org/features/Delegate.html). – maaartinus

3

La respuesta de Java a la herencia múltiple es la capacidad de implementar múltiples interfaces. Por supuesto, esto significa que obtendrá las declaraciones de métodos, pero no la lógica.

Puede intentar emular mixins por composición: su clase Java podría definir variables miembro que representen otras clases que realicen una lógica comercial común.

Al diseñar clases Java, no he encontrado la falta de herencia múltiple de estilo C++ para inhibir el diseño de mi arquitectura. Encontrarás una manera de lograr lo que quieres hacer.

17

No es la forma en que desea hacerlo. Effective Java recomienda que "Favorezca la composición sobre la herencia". Lo que significa que mueve la lógica común a otras clases y delega. Así es como se soluciona la falta de herencia múltiple en Java.

4

¿El objeto purista se agita en usted hoy?

¿Crees que podrías hacer con un poco de programación orientada a compuestos?

Entonces, señor, están buscando Apache Polygene (anteriormente Qi4J o Zest);)

+0

¿Admite características o solo mezclas? Es decir. cuando hay un conflicto b/n dos métodos con firmas idénticas, ¿uno gana, o aparece como un error del compilador y le da una forma de resolver el conflicto? –

+0

La resolución del método @NeilTraft es predecible y se basa en órdenes de declaración; consulte http://qi4j.org/_core.html#core-api-mixin – eskatos

3

QI4J le permite utilizar mixins

+0

que ahora es [Apache Zest] (https://zest.apache.org /) –

+0

Apache Zest es ahora [Apache Polygene] (http://polygene.apache.org/) – Stuporman

0

ejecución mixin sencilla/rasgos apoyan en Java utilizando CGLIB/javassit es bastante fácil. Puede echar un vistazo, por ejemplo, al here para un pequeño ejemplo. Se puede encontrar una solución más completa y lista para usar: here

2

Puede explotar el hecho de que las interfaces permiten que las clases anidadas (automáticamente públicas estáticas) mantengan la implementación predeterminada de los métodos de interfaz encapsulados dentro de la interfaz. Es decir. mover la clase BusinessLogic del ejemplo de Alex B dentro de la interfaz.

Esto es similar a la forma en Scala genera el código JVM para rasgos como se explica aquí How are Scala traits compiled into Java bytecode?

Al hacer esto el ejemplo se convierte en:

interface BusinessLogicInterface { 
    void method0(); 

    class DefaultImpl { 
     private DefaultImpl() { 
     } 

     public static void method1(BusinessLogicInterface self) { ... } 
     public static void method2(BusinessLogicInterface self) { ... } 
    } 

    void method1(); 
    void method2(); 
} 

class User extends OtherClass implements BusinessLogicInterface { 
    @Override 
    void method0() { ... } 

    @Override 
    void method1() { BusinessLogic.defaultImpl.method1(this); } 

    @Override 
    void method2() { BusinessLogic.defaultImpl.method2(this); } 
} 

Tenga en cuenta que se pasa un objeto del tipo de interfaz como el parámetro "self". Esto significa que la lógica comercial puede usar otros métodos abstractos (método0).Esto puede ser muy útil para crear un rasgo con métodos abstractos que son todos ortogonales entre sí y métodos de "extensión" de utilidad que pueden implementarse en términos de estos métodos ortogonales.

El inconveniente es que cada interfaz debe copiar/pegar el código de delegación repetitivo. Otro patrón utilizado a menudo en Java sin este inconveniente (pero con menos cohesión y menos forma OO de invocar los métodos) es crear una clase con el nombre plural como la interfaz que contiene los métodos estáticos, esto se usa en la clase de utilidad Colecciones.

+0

Tenga en cuenta que Java 8 contendrá "métodos de extensión virtuales" que permitirán exactamente mucho más fácilmente. –

0

A partir de Java-8, se agregaron los métodos de interfaz predeterminados. Esto, junto con la herencia múltiple de interfaces en Java, debería permitir algún tipo de mixin. Claramente, las interfaces deben funcionar de manera independiente. Entonces, habrá limitaciones significativas.