Benarkah metode konkret yang utama adalah bau kode? Karena saya pikir jika Anda perlu mengganti metode konkret:
public class A{
public void a(){
}
}
public class B extends A{
@Override
public void a(){
}
}
dapat ditulis ulang sebagai
public interface A{
public void a();
}
public class ConcreteA implements A{
public void a();
}
public class B implements A{
public void a(){
}
}
dan jika B ingin menggunakan kembali a () dalam A dapat ditulis ulang sebagai:
public class B implements A{
public ConcreteA concreteA;
public void a(){
concreteA.a();
}
}
yang tidak memerlukan warisan untuk mengganti metode, apakah itu benar?
virtual
kata kunci untuk mendukung penggantian. Jadi, masalah ini dibuat lebih (atau kurang) ambigu oleh rincian bahasa.final
pengubah ada persis untuk situasi seperti ini. Jika perilaku metode ini sedemikian rupa sehingga tidak dirancang untuk diganti, maka tandai sebagaifinal
. Jika tidak, harap pengembang dapat memilih untuk menimpanya.Jawaban:
Tidak, ini bukan bau kode.
Itu terletak dalam tanggung jawab masing-masing kelas untuk mempertimbangkan dengan hati-hati jika subklasifikasi sesuai, dan metode mana yang mungkin ditimpa .
Kelas dapat mendefinisikan dirinya sendiri atau metode apa pun sebagai final, atau dapat menempatkan batasan (pengubah visibilitas, konstruktor yang tersedia) tentang bagaimana dan di mana subkelasnya.
Kasus umum untuk metode utama adalah implementasi default di kelas dasar yang dapat dikustomisasi atau dioptimalkan dalam subkelas (terutama di Java 8 dengan munculnya metode default di antarmuka).
Sebuah alternatif untuk override perilaku adalah Pola Strategi , dimana perilaku tersebut disarikan sebagai interface, dan pelaksanaannya dapat diatur di kelas.
sumber
A
mengimplementasikanDescriptionProvider
?A
dapat mengimplementasikanDescriptionProvider
, dan dengan demikian menjadi penyedia deskripsi default. Tetapi idenya di sini adalah pemisahan keprihatinan:A
membutuhkan deskripsi (beberapa kelas lain mungkin juga), sementara implementasi lainnya menyediakannya.Ya, secara umum, metode beton utama adalah bau kode.
Karena metode dasar memiliki perilaku yang dikaitkan dengan itu yang biasanya dihormati pengembang, perubahan itu akan mengarah ke bug ketika implementasi Anda melakukan sesuatu yang berbeda. Lebih buruk lagi, jika mereka mengubah perilaku, implementasi Anda yang sebelumnya benar dapat memperburuk masalah. Dan secara umum, cukup sulit untuk menghormati Prinsip Substitusi Liskov untuk metode konkret non-sepele.
Sekarang, ada beberapa kasus di mana ini bisa dilakukan dan bagus. Metode semi-sepele dapat dikendarai agak aman. Metode dasar yang ada hanya sebagai jenis perilaku "waras standar" yang dimaksudkan untuk ditunggangi memiliki kegunaan yang baik.
Oleh karena itu, ini sepertinya bau bagi saya - kadang-kadang baik, biasanya buruk, lihatlah untuk memastikan.
sumber
Number
kelas denganincrement()
metode yang menetapkan nilai ke nilai valid berikutnya. Jika Anda mensubklasifikasikannya keEvenNumber
tempatincrement()
menambahkan dua alih-alih satu (dan setter memberlakukan kemerataan), proposal pertama OP memerlukan implementasi duplikat dari setiap metode di kelas dan yang kedua membutuhkan metode pembungkus tulisan untuk memanggil metode dalam anggota. Bagian dari tujuan pewarisan adalah untuk kelas anak-anak untuk memperjelas bagaimana mereka berbeda dari orang tua dengan hanya menyediakan metode-metode yang perlu berbeda.Jika itu dapat ditulis ulang dengan cara itu berarti Anda memiliki kendali atas kedua kelas. Tetapi kemudian Anda tahu apakah Anda mendesain kelas A agar diturunkan dengan cara ini dan jika Anda melakukannya, itu bukan bau kode.
Sebaliknya, jika Anda tidak memiliki kendali atas kelas dasar, Anda tidak dapat menulis ulang dengan cara itu. Jadi, apakah kelas itu dirancang untuk diturunkan dengan cara ini, dalam hal ini lanjut saja, itu bukan bau kode, atau tidak, dalam hal ini Anda memiliki dua opsi: mencari solusi lain sama sekali, atau lanjutkan saja , karena kemurnian kerja desain truf.
sumber
abstract
; tetapi ada banyak kasus di mana tidak harus. 2) jika tidak boleh diganti, itu harusfinal
(non-virtual). Tetapi masih ada banyak kasus di mana metode mungkin ditimpa. 3) jika pengembang hilir tidak membaca dokumen, mereka akan menembak diri mereka sendiri, tetapi mereka akan melakukan itu terlepas dari tindakan apa pun yang Anda lakukan.Pertama, izinkan saya menunjukkan bahwa pertanyaan ini hanya berlaku di sistem pengetikan tertentu. Misalnya, dalam pengetikan Struktural dan sistem pengetikan Bebek - suatu kelas yang hanya memiliki metode dengan nama & tanda tangan yang sama akan berarti bahwa kelas itu kompatibel dengan jenis (setidaknya untuk metode tertentu, dalam kasus pengetikan Bebek).
Ini (jelas) sangat berbeda dari ranah bahasa yang diketik secara statis , seperti Java, C ++, dll. Serta sifat pengetikan yang Kuat , seperti yang digunakan dalam Java & C ++, serta C # dan lainnya.
Saya menduga Anda berasal dari latar belakang Java, di mana metode harus secara eksplisit ditandai sebagai final jika perancang kontrak bermaksud agar mereka tidak diganti. Namun, dalam bahasa seperti C #, kebalikannya adalah default. Metode (tanpa dekorasi, kata kunci khusus) " disegel " (versi C #
final
), dan harus dinyatakan secara eksplisit seolah-virtual
olah diizinkan untuk diganti.Jika API atau pustaka telah dirancang dalam bahasa-bahasa ini dengan metode konkret yang dapat ditimpa, maka harus (setidaknya dalam beberapa kasus) masuk akal untuk ditimpa. Oleh karena itu, ini bukan bau kode untuk menggantikan metode unsealed / virtual / not
final
concrete. (Ini tentu saja mengasumsikan bahwa perancang API mengikuti konvensi dan menandaivirtual
(C #), atau menandai sebagaifinal
(Java) metode yang sesuai untuk apa yang mereka desain.)Lihat juga
sumber
Ya itu karena dapat menyebabkan panggilan super anti-pola Itu juga dapat menghilangkan tujuan awal metode ini, memperkenalkan efek samping (=> bug) dan membuat tes gagal. Apakah Anda akan menggunakan kelas yang tes unitnya merah (failling)? Saya tidak akan.
Saya akan melangkah lebih jauh dengan mengatakan, bau kode awal adalah ketika suatu metode tidak
abstract
atau tidakfinal
. Karena memungkinkan untuk mengubah (dengan mengesampingkan) perilaku entitas yang dibangun (perilaku ini dapat hilang atau diubah). Denganabstract
danfinal
maksudnya tidak ambigu:Cara paling aman untuk menambahkan perilaku ke kelas yang ada adalah apa yang ditunjukkan oleh contoh terakhir Anda: menggunakan pola dekorator.
sumber
Object.toString()
di Jawa ... Jika iniabstract
, banyak hal default tidak akan berfungsi, dan kode bahkan tidak dapat dikompilasi ketika seseorang belum menggantitoString()
metode! Jika yafinal
, keadaan akan menjadi lebih buruk - tidak ada kemampuan untuk memungkinkan objek dikonversi menjadi string, kecuali untuk cara Java. Ketika jawaban @Peter Walser berbicara tentang, implementasi standar (sepertiObject.toString()
) adalah penting. Terutama di Java 8 metode standar.toString()
itu salahabstract
ataufinal
akan menyebalkan . Pendapat pribadi saya adalah bahwa metode ini rusak dan akan lebih baik untuk tidak memilikinya sama sekali (seperti equals dan kode hash ). Tujuan awal dari standar Java adalah untuk memungkinkan evolusi API dengan retrocompatibility.