it-swarm-id.com

Apakah ada cara untuk membuat metode yang tidak abstrak tetapi harus diganti?

Apakah ada cara untuk memaksa kelas anak untuk menimpa metode kelas super non-abstrak?

Saya harus dapat membuat instance dari kelas induk, tetapi jika kelas memperluas kelas ini, ia harus memberikan definisi sendiri tentang beberapa metode.

53
user517491

Tidak ada cara langsung yang dilakukan kompiler untuk melakukan ini, sejauh yang saya tahu.

Anda bisa mengatasinya dengan bukan membuat kelas induk menjadi instantiable, tetapi sebaliknya menyediakan metode pabrik yang membuat turunan dari beberapa subkelas (mungkin pribadi) yang memiliki implementasi default:

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

Anda tidak bisa menulis new Base() sekarang, tetapi Anda dapat melakukan Base.create() untuk mendapatkan implementasi default.

37
Joachim Sauer

Seperti yang telah ditunjukkan orang lain, Anda tidak dapat melakukan ini secara langsung.

Tetapi satu cara untuk melakukan ini adalah dengan menggunakan Pola strategi , seperti:

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
        }
    }
}
24
Daniel Pryden

Pertimbangkan membuat antarmuka dengan metode ini. Keturunan kelas harus mengimplementasikannya.

6
Ivan Nikitin

Saya pikir cara termudah adalah membuat kelas abstrak yang mewarisi dari kelas dasar:


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
    }
}
5
s106mo

Ada alasan itu tidak mungkin!

Kelas turunan dapat dengan sederhana memanggil implementasi kelas dasar saat mengganti metode.

Jadi apa gunanya memaksa kelas untuk menimpa metode Anda? Saya pikir tidak ada manfaatnya.

3
Mehrdad

Tidak, itulah inti dari metode abstrak. Apa kasus penggunaan Anda? Mungkin kita dapat memikirkannya berdasarkan kebutuhan yang mendasarinya.

3
mjaggard

Bagaimana dengan ini: di dalam implementasi default metode, gunakan refleksi untuk mendapatkan Kelas objek yang tepat. Jika Kelas tidak persis sama dengan kelas dasar Anda, lempar RuntimeException atau yang setara.

public class Parent {

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

}
3
curioustechizen

Jawabannya adalah tidak. Anda dapat mendesain ulang menggunakan pola desain template. Ini dapat membantu Anda.

Atau, Anda dapat membuat kelas anak Anda mengimplementasikan antarmuka. Antarmuka mungkin atau mungkin tidak diterapkan oleh kelas super.

2
Ravi Bhatt

Anda selalu dapat membuat kelas dasar memiliki metode yang melempar pengecualian.

Secara teknis kelas dasar telah mendefinisikan metode, tetapi tidak dapat digunakan tanpa mengesampingkan metode. Dalam kasus seperti itu, saya lebih suka pengecualian runtime karena mereka tidak memerlukan pernyataan lemparan eksplisit. Contoh berikut

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

}

Kelemahannya adalah ini tidak mencegah pembuatan objek Base; Namun, siapa pun yang mencoba menggunakan salah satu metode "harus diganti" akan segera menemukan bahwa mereka harus menimpa kelas.

Meskipun solusi ini memenuhi deskripsi permintaan dengan baik, aplikasi Anda mungkin akan diuntungkan dengan tidak memerlukan solusi seperti ini. Jauh lebih baik untuk menghindari crash runtime dengan pemeriksaan kompiler, yang disediakan oleh kata kunci abstrak.

1
Edwin Buck

Saya akan mencerminkan jawaban lain dan mengatakan bahwa tidak ada cara yang dipaksakan compiler untuk memaksa kelas turunan untuk menimpa metode non-abstrak. Inti dari membuat abstrak metode adalah untuk menentukan bahwa metode dengan tanda tangan ini harus ada, tetapi tidak dapat ditentukan pada tingkat dasar dan oleh karena itu harus ditentukan pada tingkat yang diturunkan. Jika ada implementasi, implementasi non-sepele (seperti itu tidak kosong dan tidak hanya melemparkan pengecualian atau menampilkan pesan) dari metode di level dasar, maka ini tidak sepenuhnya diperlukan untuk panggilan metode dari konsumen kelas yang diturunkan untuk sukses. Jadi, kompiler tidak harus menjalankan metode utama yang bisa berjalan cukup sukses baik pada level dasar atau turunan.

Dalam situasi di mana Anda ingin kelas turunan untuk mengesampingkan implementasi kerja Anda, seharusnya sudah cukup jelas bahwa implementasi basis tidak melakukan apa yang diinginkan oleh konsumen kelas turunan; kelas dasar tidak memiliki implementasi yang cukup, atau yang salah. Dalam kasus tersebut, Anda harus percaya bahwa seorang programmer yang berasal dari kelas Anda akan tahu apa yang dia lakukan dan dengan demikian tahu bahwa metode ini perlu diganti karena tidak menghasilkan jawaban yang benar dalam konteks menggunakan objek barunya.

Saya dapat memikirkan satu hal yang dapat Anda lakukan. Dibutuhkan basis abstrak, dengan implementasi "default" yang disegel (final untuk Javaheads). Dengan begitu, ada implementasi dasar dari metode yang tersedia untuk digunakan seolah-olah itu adalah kelas "dasar", tetapi untuk mendefinisikan kelas yang berbeda untuk skenario baru, Anda harus kembali ke kelas abstrak, dan dengan demikian terpaksa menerapkan kembali metode tersebut. Metode ini bisa menjadi satu-satunya hal abstrak di kelas, sehingga masih memungkinkan Anda untuk menggunakan implementasi dasar dari metode lain:

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() { ... }
}

Namun, ini memiliki dua kelemahan. Pertama, karena Anda tidak memiliki akses ke implementasi DefaultClass melalui warisan, Anda tidak dapat memperpanjang implementasi DefaultClass, yang berarti bahwa untuk melakukan apa yang DefaultClass lakukan, ditambah sedikit lagi, Anda harus menulis ulang kode dari DefaultClass, melanggar KERING. Kedua, ini hanya berfungsi untuk satu tingkat warisan, karena Anda tidak bisa memaksa penggantian jika Anda mengizinkan warisan dari DerivedClass.

1
KeithS

mungkin ini membantu:

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
1
Rodrigo

ok, mari kita pelajari dengan cara ini. Saya mematuhi pedoman gaya Java dan menggunakan sintaksis Java. Jadi diasumsikan bahwa banyak pewarisan dan templat C++ tidak tersedia.

membuat metode kelas induk abstrak tidak harus, dalam OOP Anda menggunakan konsep polimorfisme. Anda dapat menggunakan metode yang sama dalam dua atau lebih cara berbeda. Ini disebut metode overriding.

mari kita ambil contoh.

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

ini akan mencetak "meowww !!!" di layar.

tetapi ini tidak menyiratkan bahwa metode makeSound harus diganti dalam kelas anak.

Jika Anda membutuhkan kelas anak untuk dipaksa menimpa metode, Anda lebih baik mengimplementasikan antarmuka oleh kelas.

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

ini juga akan mencetak "meowwww !!!" di layar

0
Tharindu Rusira

Ini mungkin tidak disarankan, tetapi Anda bisa membuang pengecualian (sesuatu seperti MethodeMustBeOverRiddenExp) dalam implementasi metode Anda. Tentu saja ini adalah kekuatan RunTime tetapi mungkin lebih baik daripada nuthing.

0
Itay wazana