Sebagai contoh, pertimbangkan saya memiliki kelas untuk kelas lain untuk diperluas:
public class LoginPage {
public String userId;
public String session;
public boolean checkSessionValid() {
}
}
dan beberapa subclass:
public class HomePage extends LoginPage {
}
public class EditInfoPage extends LoginPage {
}
Bahkan, subclass tidak memiliki metode untuk menimpa, juga saya tidak akan mengakses HomePage secara umum, yaitu: Saya tidak akan melakukan sesuatu seperti:
for (int i = 0; i < loginPages.length; i++) {
loginPages[i].doSomething();
}
Saya hanya ingin menggunakan kembali halaman login. Tetapi menurut https://stackoverflow.com/a/53354 , saya harus memilih komposisi di sini karena saya tidak memerlukan antarmuka LoginPage, jadi saya tidak menggunakan warisan di sini:
public class HomePage {
public LoginPage loginPage;
}
public class EditInfoPage {
public LoginPage loginPage;
}
tetapi masalahnya ada di sini, pada versi baru, kode:
public LoginPage loginPage;
duplikat ketika kelas baru ditambahkan. Dan jika LoginPage membutuhkan setter dan getter, lebih banyak kode perlu disalin:
public LoginPage loginPage;
private LoginPage getLoginPage() {
return this.loginPage;
}
private void setLoginPage(LoginPage loginPage) {
this.loginPage = loginPage;
}
Jadi pertanyaan saya adalah, apakah "komposisi atas warisan" melanggar "prinsip kering"?
sumber
extends LoginPage
semua tempat. PERIKSA MATE!LoginPage
dekorator Anda. Tidak ada lagi duplikasi, hanya yang sederhanapage = new LoginPage(new EditInfoPage())
dan Anda selesai. Atau Anda menggunakan prinsip buka-tutup untuk membuat modul otentikasi yang dapat ditambahkan ke halaman mana pun secara dinamis. Ada banyak cara untuk menangani duplikasi kode, terutama yang melibatkan menemukan abstraksi baru.LoginPage
kemungkinan adalah nama yang buruk, yang ingin Anda pastikan adalah bahwa pengguna diautentikasi saat meramban halaman itu, saat sedang diarahkan keLoginPage
atau ditampilkan pesan kesalahan yang tepat jika ia tidak.Jawaban:
Eh tunggu, Anda khawatir pengulangan itu
di dua tempat melanggar KERING? Dengan logika itu
sekarang hanya bisa ada dalam satu objek di seluruh basis kode. Bleh.
KERING adalah hal yang baik untuk diingat tetapi datanglah. Selain
semakin diduplikasi dalam alternatif Anda sehingga bahkan menjadi anal tentang KERING tidak akan masuk akal.
Kekhawatiran DRY yang valid cenderung berfokus pada perilaku identik yang diperlukan di banyak tempat yang didefinisikan di banyak tempat sehingga kebutuhan untuk mengubah perilaku ini pada akhirnya membutuhkan perubahan di banyak tempat. Buat keputusan di satu tempat dan Anda hanya perlu mengubahnya di satu tempat. Itu tidak berarti hanya satu objek yang dapat menyimpan referensi ke LoginPage Anda.
KERING seharusnya tidak diikuti secara membabi buta. Jika Anda menggandakan karena menyalin dan menempel lebih mudah daripada memikirkan metode atau nama kelas yang baik, maka Anda mungkin salah.
Tetapi jika Anda ingin meletakkan kode yang sama di tempat yang berbeda karena tempat yang berbeda dikenakan tanggung jawab yang berbeda dan cenderung perlu berubah secara mandiri, maka mungkin bijaksana untuk melonggarkan penegakan Anda terhadap KERING dan membiarkan perilaku yang identik ini memiliki identitas yang berbeda . Itu adalah pemikiran yang sama yang melarang angka ajaib.
KERING bukan hanya tentang seperti apa kode itu. Ini tentang tidak menyebarkan rincian ide sekitar dengan pengulangan tanpa alasan memaksa pengelola untuk memperbaiki hal-hal menggunakan pengulangan tanpa berpikir. Ketika Anda mencoba mengatakan pada diri sendiri bahwa pengulangan tanpa pikiran hanyalah konvensi Anda bahwa segala sesuatu mengarah pada cara yang benar-benar buruk.
Apa yang saya pikir Anda benar-benar coba untuk mengeluh disebut kode boilerplate. Ya, menggunakan komposisi daripada pewarisan menuntut kode boilerplate. Tidak ada yang terkena secara gratis, Anda harus menulis kode yang memaparkannya. Dengan boilerplate itu muncul fleksibilitas, kemampuan untuk mempersempit antarmuka yang terbuka, untuk memberikan hal-hal yang berbeda nama yang sesuai untuk tingkat abstraksi mereka, tipuan yang baik, dan Anda menggunakan apa yang Anda terdiri dari luar, bukan di dalam, jadi Anda menghadapi antarmuka normal.
Tapi ya, ini banyak mengetik keyboard ekstra. Selama saya bisa mencegah masalah yo-yo memantul ke atas dan ke bawah tumpukan warisan ketika saya membaca kode itu layak.
Sekarang bukan karena saya menolak untuk pernah menggunakan warisan. Salah satu kegunaan favorit saya adalah untuk memberikan pengecualian nama baru:
sumber
int x;
bisa ada tidak lebih dari nol kali dalam basis kodeint a; int b; int x;
saya akan mendorong untuk menghapus Anda.Kesalahpahaman umum dengan prinsip KERING adalah bahwa itu entah bagaimana terkait dengan tidak mengulangi baris kode. Prinsip KERING adalah "Setiap bagian dari pengetahuan harus memiliki representasi tunggal, tidak ambigu, otoritatif dalam suatu sistem" . Ini tentang pengetahuan, bukan kode.
LoginPage
tahu tentang cara menggambar halaman untuk login. JikaEditInfoPage
tahu bagaimana melakukan ini maka itu akan menjadi pelanggaran. TermasukLoginPage
melalui komposisi sama sekali tidak melanggar prinsip KERING.Prinsip KERING mungkin merupakan prinsip yang paling disalahgunakan dalam rekayasa perangkat lunak dan harus selalu dianggap bukan sebagai prinsip untuk tidak menduplikasi kode, tetapi sebagai prinsip untuk tidak menduplikasi pengetahuan domain abstrak. Sebenarnya, dalam banyak kasus jika Anda menerapkan KERING dengan benar maka Anda akan menduplikasi kode , dan ini tidak selalu merupakan hal yang buruk.
sumber
Jawaban singkat: ya, benar - sampai tingkat kecil yang dapat diterima.
Pada pandangan pertama, pewarisan terkadang dapat menyelamatkan Anda beberapa baris kode, karena itu memiliki efek mengatakan "kelas saya menggunakan kembali akan berisi semua metode dan atribut publik dalam cara 1: 1". Jadi jika ada daftar 10 metode dalam suatu komponen, kita tidak perlu mengulanginya dalam kode di kelas bawaan. Ketika dalam skenario komposisi 9 dari 10 metode harus diekspos secara publik melalui komponen reusing, maka kita harus menuliskan 9 delegasi panggilan, dan membiarkan yang tersisa keluar, tidak ada jalan lain untuk mengatasi hal ini.
Mengapa ini bisa ditoleransi? Lihatlah metode yang direplikasi dalam skenario komposisi - metode ini secara eksklusif mendelegasikan panggilan ke antarmuka komponen, sehingga tidak mengandung logika nyata.
Inti dari prinsip KERING adalah untuk menghindari memiliki dua tempat dalam kode di mana aturan logis yang sama dikodekan - karena ketika aturan logis ini berubah, dalam kode non-KERING mudah untuk mengadaptasi salah satu tempat itu dan melupakan yang lain, yang menyebabkan kesalahan.
Tapi karena panggilan pendelegasian tidak mengandung logika, ini biasanya tidak mengalami perubahan seperti itu, jadi tidak menyebabkan masalah nyata ketika "lebih suka komposisi daripada warisan". Dan bahkan jika antarmuka komponen berubah, yang mungkin menyebabkan perubahan formal di semua kelas menggunakan komponen, dalam bahasa yang dikompilasi kompiler akan memberi tahu kami ketika kami lupa mengubah salah satu penelepon.
Catatan untuk contoh Anda: Saya tidak tahu bagaimana penampilan
HomePage
Anda dan AndaEditInfoPage
, tetapi jika mereka memiliki fungsi login, danHomePage
(atauEditInfoPage
) adalahLoginPage
, maka warisan mungkin merupakan alat yang tepat di sini. Contoh yang kurang bisa diperdebatkan, di mana komposisi akan menjadi alat yang lebih baik dengan cara yang lebih jelas, mungkin akan membuat segalanya lebih jelas.Dengan asumsi tidak ada
HomePage
atauEditInfoPage
tidakLoginPage
, dan orang ingin menggunakan kembali yang terakhir, seperti yang Anda tulis, daripada sangat mungkin bahwa seseorang hanya memerlukan beberapa bagianLoginPage
, bukan segalanya. Jika itu masalahnya, pendekatan yang lebih baik daripada menggunakan komposisi dengan cara yang ditunjukkan mungkin untukekstrak bagian yang dapat digunakan kembali
LoginPage
menjadi komponennya sendirimenggunakan kembali komponen itu
HomePage
danEditInfoPage
cara yang sama digunakan sekarang di dalamLoginPage
Dengan begitu, biasanya akan menjadi jauh lebih jelas mengapa dan kapan komposisi atas warisan adalah pendekatan yang tepat.
sumber