2016-03-30 19 views
2

Lassen Sie uns dieses Beispiel betrachten:Polymorphism - bauen ein Objekt des gleichen Typs

class InheritedType extends Type { 

    public Type simplify() { 
     Type newLeft = left.simplify(); 
     Type newRight = right.simplify(); 
     Type newExpr = new InheritedType(newLeft, newRight); 
     return newExpr.simplify(); 
    } 
} 

Nun möchte ich einen anderen ererbten Typ erstellen

class InheritedType2 extends Type { 

    public Type simplify() { 
     Type newLeft = left.simplify(); 
     Type newRight = right.simplify(); 
     Type newExpr = new InheritedType2(newLeft, newRight); 
     return newExpr.simplify(); 
    } 
} 

Diese Methode ist genau das gleiche, nur der Konstruktor Namen unterscheidet sich. Gibt es eine Möglichkeit, Code-Duplizierung zu vermeiden? Der folgende Code funktioniert nicht

class Type { 

    public Type simplify() { 
     Type newLeft = left.simplify(); 
     Type newRight = right.simplify(); 
     Type newExpr = new this(newLeft, newRight); 
     return newExpr.simplify(); 
    } 
} 
+0

Ihr Code wirklich keinen Sinn macht. Jeder Aufruf von 'simplify' endet mit einem rekursiven Aufruf von' simplify'. Ihre Methoden beziehen sich auf Felder, die nicht deklariert sind. Daher ist nicht klar, wo sie deklariert werden sollen. Sie sollten ein minimales * korrekt * Beispiel posten, wenn Sie nützlichen Rat brauchen. – ruakh

Antwort

4

Der typische Weg, um dieses Problem ist es, eine gemeinsame übergeordnete Klasse für InheritedType und InheritedType2 einzuführen. Dies liegt daran, dass diese beiden Typen offensichtlich eine gemeinsame Logik haben: Sie operieren sowohl auf linken als auch auf rechten Operanden. Also lassen Sie uns erstellen LeftRightType (mangels eines besseren Namens):

abstract class LeftRightType extends Type { 

    private Type left, right; 

    public LeftRightType(Type left, Type right) { 
     this.left = left; 
     this.right = right; 
    } 

    @Override 
    public Type simplify() { 
     return newInstance(left.simplify(), right.simplify()).simplify(); 
    } 

    public abstract Type newInstance(Type left, Type right); 

} 

Er hält die Logik, die Sie zur Zeit duplizieren und delegieren die Schaffung der konkreten Instanz in eine newInstance abstrakte Methode, die Implementierer überschreiben. Dann können Sie einfach haben

class InheritedType extends LeftRightType { 
    public InheritedType(Type left, Type right) { 
     super(left, right); 
    } 
    @Override 
    public Type newInstance(Type left, Type right) { 
     return new InheritedType(left, right); 
    } 
} 

class InheritedType2 extends LeftRightType { 
    public InheritedType2(Type left, Type right) { 
     super(left, right); 
    } 
    @Override 
    public Type newInstance(Type left, Type right) { 
     return new InheritedType2(left, right); 
    } 
} 

Beachten Sie, dass wenn Sie mit Java 8 können Sie verdichten, dass eine Menge von der konkreten Klasse geben direkt im Konstruktor zurückzukehren. Sie brauchen nicht einmal mehr eine abstrakte Methode.

abstract class LeftRightType extends Type { 

    private Type left, right; 
    private BinaryOperator<Type> typeSupplier; 

    public LeftRightType(Type left, Type right, BinaryOperator<Type> typeSupplier) { 
     this.left = left; 
     this.right = right; 
     this.typeSupplier = typeSupplier; 
    } 

    public Type simplify() { 
     return typeSupplier.apply(left.simplify(), right.simplify()).simplify(); 
    } 
} 

und dann haben

class InheritedType extends LeftRightType { 
    public InheritedType(Type left, Type right) { 
     super(left, right, InheritedType::new); 
    } 
} 

class InheritedType2 extends LeftRightType { 
    public InheritedType2(Type left, Type right) { 
     super(left, right, InheritedType2::new); 
    } 
} 
2

Sie können Sie „seltsam wiederkehrende Vorlage Muster“ https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern:

abstract class Type<This extends Type<This>> { 
    protected abstract This newInstance(Type<?> newLeft, Type<?> newRight); 

    public This simplify() { 
     Type<?> newLeft = left.simplify(); 
     Type<?> newRight = right.simplify(); 
     This newExpr = newInstance(newLeft, newRight); 
     return newExpr.simplify(); 
    } 
} 

class InheritedType extends Type<InheritedType> { 
    protected InheritedType newInstance(Type<?> left, Type<?> right) { 
     new InheritedType(left, right); 
    } 
} 

class InheritedType2 extends Type<InheritedType2> { 
    protected InheritedType2 newInstance(Type<?> left, Type<?> right) { 
     new InheritedType2(left, right); 
    } 
} 
Verwandte Themen