2010-04-06 13 views
12

Ich habe eine abstrakte Klasse Baseclass mit einer öffentlichen insert() Methode:Überlast- und verstecken Methoden in Java

public abstract class BaseClass { 

public void insert(Object object) { 
    // Do something 
} 

} 

, die von vielen anderen Klassen erweitert. Für einige dieser Klassen müssen jedoch die insert() Methode zusätzliche Parameter haben, so dass sie, anstatt sie zu überschreiben ich die Methode der Basisklasse mit den erforderlichen Parameter überlasten, zum Beispiel:

public class SampleClass extends BaseClass { 

public void insert(Object object, Long param){ 
    // Do Something 
} 

} 

Nun, wenn i die Sample Klasse instanziiert, ich habe zwei insert() Methoden:

SampleClass sampleClass = new SampleClass(); 
sampleClass.insert(Object object); 
sampleClass.insert(Object object, Long param); 

was ich mag ist tun, um die insert() Methode in der Basisklasse definiert verstecken, so dass nur die Überlastung zu sehen sein würde:

SampleClass sampleClass = new SampleClass(); 
sampleClass.insert(Object object, Long param); 

Könnte dies in OOP geschehen?

Antwort

18

Es gibt keine Möglichkeit verstecken die Methode. Sie können dies tun:

@Override 
public void insert(Object ob) { 
    throw new UnsupportedOperationException("not supported"); 
} 

aber das ist es.

Die Basisklasse erstellt einen Vertrag. Alle Unterklassen sind an diesen Vertrag gebunden. Denken Sie an es auf diese Weise:

BaseObject b = new SomeObjectWithoutInsert(); 
b.insert(...); 

Wie ist das Code zu wissen, bedeutet, dass es keine insert(Object) Methode hat? Es kann nicht.

Ihr Problem klingt wie ein Designproblem. Entweder sollten die fraglichen Klassen nicht von der fraglichen Basisklasse erben oder diese Basisklasse sollte diese Methode nicht haben. Vielleicht können Sie insert() aus dieser Klasse nehmen, es in eine Unterklasse verschieben und Klassen haben, die insert(Object) erweitern müssen, und diejenigen, die insert(Object, Object) benötigen, erweitern eine andere Unterklasse des Basisobjekts.

6

Ich glaube nicht, dass es eine saubere Möglichkeit gibt, eine geerbte Methode in Java vollständig zu verstecken.

In solchen Fällen, wenn Sie diese Methode absolut nicht unterstützen können, würde ich diese Methode wahrscheinlich als @Obsolete in der Kindklasse markieren und eine NotImplementedException (oder was auch immer die entsprechende Ausnahme in Java ist) auslösen. um Menschen davon abzuhalten, sie zu benutzen.

Wenn Sie schließlich eine Methode erben, die für Ihre untergeordnete Klasse keinen Sinn ergibt, könnte es sein, dass Sie überhaupt nicht von dieser Basisklasse erben sollten. Es kann auch sein, dass die Basisklasse schlecht entworfen ist oder zu viel Verhalten umfasst, aber es könnte sich lohnen, die Klassenhierarchie zu betrachten. Ein anderer zu betrachtender Weg könnte die Komposition sein, in der Ihre Klasse eine private Instanz der früheren Basisklasse hat, und Sie können auswählen, welche Methoden verfügbar gemacht werden sollen, indem Sie sie in Ihre eigenen Methoden einschließen. (Bearbeiten: Wenn die Basisklasse abstrakt ist, Zusammensetzung möglicherweise keine Option ...)

1

Wie Cletus darauf hinweist, handelt es sich hierbei um ein Designproblem, da Sie versuchen, eine untergeordnete Klasse zu erstellen, die nicht dem Vertrag der übergeordneten Klasse entspricht.

Es gibt seltene Umstände, in denen dies z.Eine Exception auszulösen könnte wünschenswert sein (oder zumindest ein akzeptabler Kompromiss - zum Beispiel das Java Collections Framework), aber im Allgemeinen ist es ein Zeichen für schlechtes Design.

the Liskov substitution principle: die Idee, die (wie Wikipedia es ausdrückt) "wenn S ein Subtyp von T ist, dann können Objekte vom Typ T in einem Programm durch Objekte vom Typ S ersetzt werden, ohne sie zu verändern der wünschenswerten Eigenschaften dieses Programms ". Indem Sie eine Methode außer Kraft setzen, um eine Ausnahme auszulösen oder sie auf andere Weise zu verbergen, verletzen Sie dieses Prinzip.

Wenn der Vertrag der Methode der Basisklasse "das aktuelle Objekt einfügt oder eine Ausnahme auslöst" (siehe z. B. the JavaDoc for Collection.add()), könnten Sie argumentieren, dass Sie LSP nicht verletzen, aber wenn die meisten Anrufer dies nicht erwarten Vielleicht möchten Sie aus diesem Grund Ihr Design überdenken.

1

Das klingt wie eine schlecht gestaltete Hierarchie -

Wenn kein Standardwert vorhanden ist und der Benutzer die Methode überhaupt nicht nennen sollten Sie die Methode als @Deprecated markieren und haben eine UnsupportedOperationException wie andere Plakate bemerkt werfen. Allerdings - das ist wirklich nur eine Laufzeitprüfung. @Deprecated löst nur eine Compiler-Warnung aus und die meisten IDEs markieren sie in irgendeiner Weise, aber es gibt keine Kompilierzeit-Verhinderung davon. Es ist auch wirklich nervtötend, weil es möglich ist, die Kindklasse als Elternklassenreferenz zu erhalten und die Methode darauf aufzurufen, ohne zu warnen, dass sie überhaupt "schlecht" ist. Im folgenden Beispiel wird erst zur Laufzeit angezeigt, dass etwas nicht stimmt.

Beispiel:

// Abstract base builder class 
public abstract class BaseClassBuilder { 
    public final doBuild() { 
     BaseClass base = getBase(); 
     for (Object obj : getObjects() { 
      base.insert(obj); 
     } 
    } 
    protected abstract BaseClass getBase(); 
    protected abstract Object[] getObjects(); 
} 

// implementation using SampleClass 
public class SampleClassBuilder extends BaseClassBuilder { 

    @Override 
    protected BaseClass getBase() { 
     return new SampleClass(); 
    } 

    @Override 
    protected Object[] getObjects() { 
     Object[] obj = new Object[12]; 
     // ... 
     return obj; 
    } 
} 

Wenn jedoch ein sinnvoller Standardwert vorhanden ist, können Sie die geerbte Methode als Endnote und den Standardwert in der es schaffen. Dies behandelt sowohl die schlechte Hierarchie als auch die "unvorhergesehenen Umstände" des obigen Beispiels.

Beispiel:

public abstract class BaseClass { 
    public void insert(Object object) { 
     // ... 
    } 
} 

public class SampleClass extends BaseClass { 

    public static final Long DEFAULT_PARAM = 0L; 

    public final void insert(Object object) { 
     this.insert(object, DEFAULT_PARAM); 
    } 

    public void insert(Object object, Long param) { 
     // ... 
    } 
} 
Verwandte Themen