Gibt es eine Möglichkeit, eine Methode zu erstellen, die nicht abstrakt ist, sondern überschrieben werden muss?

StackOverflow https://stackoverflow.com/questions/7832444

Frage

Gibt es eine Möglichkeit, untergeordnete Klassen zu zwingen, eine nicht abstrakte Methode der Superklasse zu überschreiben?

Ich muss in der Lage sein, Instanzen der übergeordneten Klasse zu erstellen, aber wenn eine Klasse diese Klasse erweitert, muss sie einige Methoden selbst definieren.

War es hilfreich?

Lösung

Soweit ich weiß, gibt es keine direkte, vom Compiler erzwungene Möglichkeit, dies zu tun.

Sie können dies umgehen, indem Sie nicht die übergeordnete Klasse instanziierbar machen, sondern stattdessen eine Factory-Methode bereitstellen, die eine Instanz einer (möglichen privaten) Unterklasse mit der Standardimplementierung erstellt:

public abstract class Base {
  public static Base create() {
    return new DefaultBase();
  }

  public abstract void frobnicate();

  static class DefaultBase extends Base {
    public void frobnicate() {
      // default frobnication implementation
    }
  }
}

Sie können jetzt keinen new Base() schreiben, aber Sie können Base.create() ausführen, um die Standardimplementierung zu erhalten.

Andere Tipps

Wie andere bereits betont haben, können Sie dies nicht direkt tun.

Eine Möglichkeit, dies zu tun, besteht darin, das Strategiemuster wie folgt zu verwenden:

public class Base {
    private final Strategy impl;

    // Public factory method uses DefaultStrategy
    // You could also use a public constructor here, but then subclasses would
    // be able to use that public constructor instead of the protected one
    public static Base newInstance() {
        return new Base(new DefaultStrategy());
    }

    // Subclasses must provide a Strategy implementation
    protected Base(Strategy impl) {
        this.impl = impl;
    }

    // Method is final: subclasses can "override" by providing a different
    // implementation of the Strategy interface
    public final void foo() {
        impl.foo();
    }

    // A subclass must provide an object that implements this interface
    public interface Strategy {
        void foo();
    }

    // This implementation is private, so subclasses cannot access it
    // It could also be made protected if you prefer
    private static DefaultStrategy implements Strategy {
        @Override
        public void foo() {
            // Default foo() implementation goes here
        }
    }
}

Erstellen Sie eine Schnittstelle mit dieser Methode.Klassennachkommen müssen es implementieren.

Ich denke, der einfachste Weg ist, eine abstrakte Klasse zu erstellen, die von der Basisklasse erbt:


public class Base {
    public void foo() {
        // original method
    }
}

abstract class BaseToInheritFrom extends Base {
    @Override
    public abstract void foo();
}

class RealBaseImpl extends BaseToInheritFrom {
    @Override
    public void foo() {
        // real impl
    }
}

Nein, das ist der springende Punkt einer abstrakten Methode.Was ist Ihr Anwendungsfall?Vielleicht können wir basierend auf dem zugrunde liegenden Bedarf darüber nachdenken.

Wie wäre es damit: Verwenden Sie in der Standardimplementierung der Methode Reflection, um die genaue Klasse des Objekts abzurufen.Wenn die Klasse nicht genau mit Ihrer Basisklasse übereinstimmt, lösen Sie eine RuntimeException oder eine gleichwertige aus.

public class Parent {

    public void defaultImpl(){
        if(this.getClass() != Parent.class){
            throw new RuntimeException();
        }
    }

}

Es gibt einen Grund , warum dies nicht möglich ist!

Die abgeleitete Klasse kann beim Überschreiben der Methode einfach die Implementierung der Basisklasse aufrufen.

Was bringt es also, die Klasse zu zwingen, Ihre Methode zu überschreiben?Ich glaube nicht, dass es irgendeinen Vorteil gibt.

Antwort wäre ein Nein.Sie können mithilfe des Vorlagenentwurfsmusters neu gestalten.Es kann Ihnen helfen.

Alternativ können Sie Ihre untergeordneten Klassen eine Schnittstelle implementieren lassen.Die Schnittstelle kann von der Superklasse implementiert werden oder nicht.

Sie können der Basisklasse jederzeit eine Methode zuweisen, die eine Ausnahme auslöst.

Technisch gesehen hat die Basisklasse die Methode definiert, sie kann jedoch nicht verwendet werden, ohne die Methode zu überschreiben.In einem solchen Fall bevorzuge ich eine Laufzeitausnahme, da keine explizite throw-Anweisung erforderlich ist.Ein Beispiel folgt

public class Parent {

  public void doStuff() {
    throw new RuntimeException("doStuff() must be overridden");
  }

}

public class Child extends Parent {

  @Override
  public void doStuff() {
    ... all is well here ...
  }

}

Der Nachteil ist, dass dies die Erstellung von Base-Objekten nicht verhindert.Jeder, der versucht, eine der Methoden "muss überschrieben werden" zu verwenden, wird jedoch bald feststellen, dass er die Klasse hätte überschreiben müssen.

Während diese Lösung die Beschreibung der Anforderung gut erfüllt, würde Ihre Anwendung wahrscheinlich davon profitieren, keine solche Lösung zu benötigen.Es ist viel besser, Laufzeitabstürze mit Compilerprüfungen zu vermeiden, was das abstrakte Schlüsselwort bietet.

Ich werde die anderen Antworten spiegeln und sagen, dass es keine vom Compiler erzwungene Möglichkeit gibt, abgeleitete Klassen zu zwingen, eine nicht abstrakte Methode zu überschreiben. Der Sinn einer abstrakten Methode besteht darin, zu definieren, dass eine Methode mit dieser Signatur vorhanden sein muss, jedoch nicht auf der Basisebene angegeben werden kann und daher auf einer abgeleiteten Ebene angegeben werden muss. Wenn es eine funktionierende, nicht triviale Implementierung (da sie nicht leer ist und nicht nur eine Ausnahme auslöst oder eine Nachricht anzeigt) einer Methode auf der Basisebene gibt, ist dies für einen Aufruf von nicht unbedingt erforderlich die Methode von einem Konsumenten der abgeleiteten Klasse, um erfolgreich zu sein. Der Compiler muss also nicht das Überschreiben einer Methode erzwingen, die entweder auf der Basis- oder auf der abgeleiteten Ebene recht erfolgreich ausgeführt werden kann.

In Situationen, in denen eine abgeleitete Klasse Ihre Arbeitsimplementierung überschreiben soll, sollte es ziemlich offensichtlich sein, dass die Basisimplementierung nicht das tut, was die Verbraucher der abgeleiteten Klasse wollen. Die Basisklasse hat entweder nicht genügend oder die falsche Implementierung. In diesen Fällen müssen Sie darauf vertrauen, dass ein aus Ihrer Klasse stammender Programmierer weiß, was er tut, und daher weiß, dass die Methode überschrieben werden muss, da sie im Zusammenhang mit der Verwendung seines neuen Objekts nicht die richtige Antwort liefert.

Ich kann mir eine Sache vorstellen, die Sie tun könnten. Es würde eine abstrakte Basis mit einer versiegelten (endgültig für die Javaheads) "Standard" -Implementierung erfordern. Auf diese Weise gibt es eine grundlegende Implementierung der Methode, die leicht verfügbar ist, als wäre sie eine "Basis" -Klasse. Um jedoch eine andere Klasse für ein neues Szenario zu definieren, müssen Sie zur abstrakten Klasse und zurückkehren sind daher gezwungen, die Methode erneut umzusetzen. Diese Methode könnte die einzige abstrakte Sache in der Klasse sein, sodass Sie weiterhin grundlegende Implementierungen anderer Methoden verwenden können:

public abstract class BaseClass
{
   public abstract void MethodYouMustAlwaysOverride();

   public virtual void MethodWithBasicImplementation() { ... }
}

public final class DefaultClass:BaseClass
{
   public override void MethodYouMustAlwaysOverride() { ... }

   //the base implementation of MethodWithBasicImplementation 
   //doesn't have to be overridden
}

...

public class DerivedClass:BaseClass
{
   //Because DefaultClass is final, we must go back to BaseClass,
   //which means we must reimplement the abstract method
   public override void MethodYouMustAlwaysOverride() { ... }

   //again, we can still use MethodWithBasicImplementation, 
   //or we can extend/override it
   public override void MethodWithBasicImplementation() { ... }
}

Dies hat jedoch zwei Nachteile. Erstens können Sie die Implementierung von DefaultClass nicht erweitern, da Sie keinen Zugriff auf die Implementierung von DefaultClass durch Vererbung haben. Dies bedeutet, dass Sie den Code von DefaultClass neu schreiben müssen, um DRY zu verletzen. Zweitens funktioniert dies nur für eine Vererbungsebene, da Sie das Überschreiben nicht erzwingen können, wenn Sie die Vererbung von DerivedClass zulassen.

Vielleicht hilft das:

class SuperClass {

    void doStuff(){

        if(!this.getClass().equals(SuperClass.class)){

            throw new RuntimeException("Child class must implement doStuff Method");
        }else{
            //ok
            //default implementation
        }
    }
}

class Child extends SuperClass{

    @Override
    void doStuff() {
        //ok
    }
}

class Child2 extends SuperClass{

}


 new SuperClass().doStuff(); //ok
 new Child().doStuff();         //ok
 new Child2().doStuff();        //error

ok, lass es uns so lernen.Ich halte mich an die Richtlinien für den Java-Stil und verwende die Java-Syntax.Daher wird davon ausgegangen, dass Mehrfachvererbungs- und C ++ - Vorlagen nicht verfügbar sind.

Die übergeordnete Klassenmethode abstrakt zu machen ist kein Muss. In OOP verwenden Sie das Konzept des Polymorphismus.Sie können dieselbe Methode auf zwei oder mehr verschiedene Arten verwenden. Dies wird als Methodenüberschreibung bezeichnet.

Nehmen wir ein Beispiel.

    public class Animal{
       public void makeSound(){
          System.out.println("Animal doesn't know how to make sound");
       }

    }

    public class PussyCat extends Animal{
        public void makeSound(){

           System.out.println("meowwww !!!");
        }

        public static void main(String args[]){
           PussyCat aCat=new PussyCat();
           aCat.makeSound(); 
        }
    }

dies wird "meowww !!!"auf dem Bildschirm.

Dies bedeutet jedoch nicht, dass die Methode makeSound in der untergeordneten Klasse überschrieben werden muss.

Wenn die untergeordnete Klasse gezwungen werden muss, die Methoden zu überschreiben, implementieren Sie besser eine Schnittstelle durch die Klasse.

      public Interface audible{
         public void makeSound();

      }

      public class pussyCat implements audible{
          // now you must implement the body of makeSound method here
          public void makeSound(){
            System.out.println("meowwww !!!"); 
          }

          public static void main(String args[]){
           PussyCat aCat=new PussyCat();
           aCat.makeSound(); 
        }
      }

dies wird auch "meowwww !!!"auf dem Bildschirm

Es wird möglicherweise nicht empfohlen, aber Sie können eine Ausnahme (so etwas wie MethodeMustBeOverRiddenExp) in Ihre Methodenimplementierung einfügen. Natürlich ist es RunTime Forcing, aber möglicherweise besser als Nuthing.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top