Apakah bahasa OO mendukung mekanisme untuk menjamin metode overriden akan memanggil basis?

12

Saya pikir ini mungkin fitur bahasa yang berguna dan bertanya-tanya apakah ada bahasa yang mendukungnya.

Idenya adalah jika Anda memiliki:

class C
  virtual F
     statement1
     statement2

dan

class D inherits C
  override F
     statement1
     statement2
     C.F()

Akan ada kata kunci yang diterapkan pada CF () sehingga menghapus baris terakhir dari kode di atas akan menyebabkan kesalahan kompiler karena mengatakan "Metode ini dapat diganti tetapi implementasi di sini perlu dijalankan tidak peduli apa".

Aaron Anodide
sumber

Jawaban:

14

Ya mereka melakukanya. Ini disebut model Skandinavia OO, digunakan misalnya dalam Simula (model OO lain yang tersebar luas dan diterima seperti yang sekarang, adalah model Amerika). Dalam model Skandinavia, Anda tidak mengesampingkan, tetapi memasok sub-perilaku.

dalam metode foo Superclass:

some-code-before
INNER // this is the actual Simula keyword
some-code-after

dalam metode Subclass 'foo:

some-code-in-subclass

Jika Anda memanggil metode 'instance' Superclass foo, hanya some-code-beforedan some-code-afterterjadi ( INNERtidak melakukan apa-apa), tetapi jika Anda menyebut Subclass 'instance' foo, itu benar some-code-before, some-code-in-subclassdan kemudian some-code-after.

herba
sumber
9

Tidak ada bahasa yang saya tahu tentang penegakan yang memanggil metode yang diganti. Memang, beberapa bahasa memungkinkan metode penggantian yang tidak dapat ditimpa (seperti menggunakan newkata kunci dalam C #). Namun, ada dua cara untuk mendekati ini.

Yang pertama adalah membuat metode yang tidak dapat diedit (mis. Yang tidak memiliki virtualkata kunci dalam C # atau yang memiliki finalkata kunci di Jawa) yang memanggil metode yang tidak dapat dipanggil yang tidak dapat dipanggil dari luar kelas (misalnya protecteddalam C #, Java atau C ++).

class C
  A
     statement1
     F
     statement3

  protected virtual F
     statement2

dan

class D inherits C

  protected override F
     statement4
     C.F()

Kelas overriding Cbebas untuk menimpa Fdan memodifikasi perilakunya tetapi penelepon dari luar kelas hanya mengaksesnya A.

Sunting: Seperti yang telah ditunjukkan orang lain, ini disebut pola metode Templat .

Cara kedua adalah menggunakan bahasa yang memberlakukan prasyarat dan prasyarat yang ditentukan dalam kelas dasar, seperti Eiffel atau C # dengan Kontrak Kode. Itu tidak akan memaksa kelas dasar untuk dipanggil tetapi metode yang ditimpa dapat dipaksa untuk melakukan pernyataan yang sama. Menggunakan aspek juga dapat membantu jika bahasa memungkinkan aspek diwariskan.

akton
sumber
2
Anda bahkan dapat membuat metode yang akan ditimpa privatedalam C ++ :) Herb Sutter menjelaskannya di sini secara rinci.
fredoverflow
Pola template hanya memiliki satu kelemahan yang Anda butuhkan untuk mengimplementasikannya setiap kali sambil mempelajari hierarki warisan lebih dalam. Contoh dengan Simula lebih elegan dan masih memungkinkan untuk pola template.
Pavel Voronin
7

Tidak benar-benar bagian dari bahasa, tetapi penganalisa kode statis FindBugs untuk Java memiliki anotasi OverrideMustInvokeyang dapat ditambahkan oleh pengembang ke metode, dan yang akan menyebabkan FindBugs menunjukkan kesalahan jika menemukan metode override yang tidak memanggil super implementasi . Bahkan memungkinkan menentukan apakah panggilan harus menjadi yang pertama atau terakhir dalam metode utama.

Michael Borgwardt
sumber
6

Diperlukan untuk memanggil metode superclass adalah anti-pola . Jika tidak diberlakukan pada waktu kompilasi, itu rawan kesalahan, itulah sebabnya Anda mencari konstruksi bahasa yang memeriksanya.

Ada cara yang didukung dalam semua bahasa OO: Pola metode templat . Di sini, Anda membuat metode superclass tidak dapat ditimpa, dan di dalamnya Anda memanggil metode yang dapat ditimpa. Subclass kemudian dapat mengganti metode ini untuk menambahkan fungsionalitas:

class super {
  public final void doSomething() {
    doSpecialthing();
    doMore();
  }
  public void doSpecialthing() {
  }
}

Bergantung pada lokasi panggilan ke metode yang diganti bahkan memungkinkan untuk menentukan urutan eksekusi, yang dengan panggilan super biasa adalah atas kehendak pelaksana subkelas.

Ozan
sumber
1

Pola terdekat yang bisa saya pikirkan adalah acara berlangganan sendiri. Agak rumit, dan sama sekali tidak intuitif untuk pembuat kode, tetapi mencapai tujuannya.

class C
{
    public void F()
    {
        ...
        OnF()
    }

    protected event OnF
}

class D : C
{
    public D()
    {
        base.OnF += this.F
    }

    private void F
    {
        ...
    }
}
Makanan Tangan
sumber
1
Ini adalah pola desain yang cukup umum, terkadang dengan pro dan post override misalnya. ViewWillAppear (), ViewDidAppear (). Ideal saat Anda ingin memperbolehkan subclass untuk memperluas (alih-alih memodifikasi) perilaku default.
Kris Van Bael
1

Mesin Lisp "rasa" memungkinkan metode dengan mengetik "sebelum" "setelah" dan "sekitar" metode utama yang diwarisi.

ddyer
sumber
0

Meskipun bukan ide yang buruk dalam teori, itu memang memiliki efek samping negatif dari membatasi pilihan saya ketika menerapkan D. Misalnya, bagaimana jika (karena alasan yang tidak terduga), lebih mudah untuk memanggil implementasi superclass Fdari beberapa metode lain:

class D inherits C
    override F
        statement1
        statement2
        G()
    G
        statement3
        C.F()
        statement4

Di bawah skenario Anda, saya membayangkan kompiler akan menandai implementasi Fdi D, meskipun ia memanggil (secara tidak langsung) C.F().

Pada dasarnya, apa yang telah Anda jelaskan adalah mekanisme yang memungkinkan untuk membantu kompiler mengenali ketika kontrak pada kelas yang diwarisi dari Cdilanggar. Maksud saya adalah, walaupun itu adalah hal yang hebat, itu tidak harus dengan mengorbankan membatasi bagaimana saya dapat mengimplementasikan subclass saya.

Mac
sumber
1
-1: bisa memikirkan situasi di mana Anda tidak ingin menggunakan itu bukan jawaban untuk pertanyaan "apakah bahasa apa pun mengizinkan itu".
@ GrahamLee: sangat benar. Maksud saya adalah mencoba dan menjelaskan satu alasan mengapa tidak ada bahasa (yang saya ketahui) mengimplementasikan fitur seperti itu. Saya kira saya begitu terjebak dalam menjelaskan hal itu, sehingga saya lupa menyebutkan mengapa saya menjelaskannya. -1 diterima dengan senang hati. :)
Mac