2012-05-27 20 views
5

Ho una domanda teorica su come affrontare lo scenario seguente in una lingua che non consente l'ereditarietà multipla.Eredità multipla senza ereditarietà multipla e senza duplicazione del codice

Immaginate Ho una classe di base Foo e da esso sto volendo creare tre sottoclassi:

  • Classe Bar eredita Foo e implementa la funzionalità "A"
  • Class Baz eredita Foo e implementa la funzionalità "B"
  • Classe Qux eredita Foo ed implementa le funzionalità "A" e "B"

Immaginate che il codice per implementare funzionalità "A" e "B" è sempre la stessa. C'è un modo per scrivere il codice per "A" e "B" solo una volta, e poi applicare le classi appropriate (o "ereditarlo")?

+0

Qualsiasi lingua particolare? Giava? C#? Qualcos'altro? – Tudor

+0

Perché non si sta implementando la stessa funzionalità all'interno della classe FOO e si contrassegna A/B come virtuale/sovrascrivibile? – YavgenyP

+0

@Tudor Pensava in C# ma qualsiasi linguaggio OOP che non consenta l'ereditarietà multipla va bene. –

risposta

3

Ebbene l'unico modo che posso vederti raggiungere questo in C#/Java è di composizione. Considerate questo:

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();   
    }  
} 

Ora Qux ha sia la funzionalità di Foo tramite ereditarietà normale, ma anche le implementazioni di A e B di composizione.

1

Questo è realizzabile in lingue che fornisce caratteristiche (qui: ):

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 {} 

Perché Scala esegue all'inizio di Java (non avendo né l'ereditarietà multipla, né tratti) si traduce in qualcosa di simile (semplificato) - che potrebbe essere un indizio come implementarlo in 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

Il termine più generale per questo è un Mixin. Alcune lingue forniscono supporto immediato, come Scala e D. Ci sono vari modi per ottenere gli stessi risultati in altre lingue.

Un modo per creare una pseudo-mixin in C# consiste nell'utilizzare interfacce vuote e fornire i metodi con i metodi di estensione.

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

Ci sono diversi modi per fare qualcosa di simile. Nello specifico, se abbandoniamo per un momento l'aspetto dell'ereditarietà, ci sono modi per introdurre la stessa unità di funzionalità in classi diverse, mentre si scrive l'unità solo una volta.

Ok, I amoreAOP Frameworks, ed esistono per molte lingue (C# e Java che hanno diversi). I framework AOP consentono fondamentalmente di aggiungere funzionalità autonome in classi diverse all'interno della struttura di ereditarietà.

Per C#, si dispone di PostSharp e per Java si dispone di AspectJ, tra molti altri.

Molti framework AOP consentono chiamate "hijacking" o "override" senza utilizzare l'ereditarietà.