Saya memiliki antarmuka yang memiliki sejumlah fungsionalitas yang terdefinisi dengan baik. Katakanlah:
interface BakeryInterface {
public function createCookies();
public function createIceCream();
}
Ini berfungsi dengan baik untuk sebagian besar implementasi antarmuka, tetapi dalam beberapa kasus, saya perlu menambahkan beberapa fungsi baru (seperti mungkin digulirkan ke metode baru, createBrownies()
). Pendekatan yang jelas / naif untuk melakukan ini adalah memperluas antarmuka:
interface BrownieBakeryInterface extends BakeryInterface {
public function createBrownies();
}
Tetapi memiliki kelemahan yang cukup besar karena saya tidak dapat menambahkan fungsionalitas baru tanpa memodifikasi API yang ada (seperti mengubah kelas untuk menggunakan antarmuka baru).
Saya sedang berpikir tentang menggunakan adaptor untuk menambah fungsionalitas setelah instantiation:
class BrownieAdapter {
private brownieBakery;
public function construct(BakeryInterface bakery) {
this->brownieBakery = bakery;
}
public function createBrownies() {
/* ... */
}
}
Yang akan memberi saya sesuatu seperti:
bakery = new Bakery();
bakery = new BrownieBakery(bakery);
bakery->createBrownies();
Ini sepertinya solusi yang bagus untuk masalah ini, tetapi saya bertanya-tanya apakah saya membangunkan dewa-dewa lama dengan melakukannya. Apakah adaptor bisa digunakan? Apakah ada pola yang lebih baik untuk diikuti? Atau haruskah saya benar-benar menggigit peluru dan hanya memperluas antarmuka asli?
Jawaban:
Salah satu Handle pola Tubuh bisa cocok dengan deskripsi, tergantung pada persyaratan yang tepat Anda, bahasa, dan tingkat yang diperlukan abstraksi.
Pendekatan murni adalah pola dekorator , yang melakukan persis apa yang Anda cari, secara dinamis menambah tanggung jawab pada objek. Jika Anda benar-benar membangun toko roti, itu pasti berlebihan dan Anda hanya harus menggunakan Adaptor.
sumber
Selidiki konsep penggunaan kembali horisontal , di mana Anda dapat menemukan hal-hal seperti Ciri , Pemrograman Berorientasi Aspek yang masih eksperimental namun sudah produksi dan Mixin yang terkadang dibenci .
Cara langsung menambahkan metode ke kelas juga tergantung pada bahasa pemrograman. Ruby memungkinkan untuk menambal-monyet sementara warisan Javascript's prototipe , di mana kelas tidak benar-benar ada, Anda membuat objek dan hanya menyalinnya dan terus menambahkannya, misalnya:
Akhirnya, Anda juga dapat meniru penggunaan kembali horisontal, atau "modifikasi" runtime dan "penambahan" perilaku kelas / objek dengan refleksi .
sumber
Jika ada persyaratan bahwa
bakery
instance harus mengubah perilakunya secara dinamis (tergantung pada tindakan pengguna, dll.) Maka Anda harus menggunakan pola Penghias .Jika
bakery
tidak mengubah perilakunya secara dinamis tetapi Anda tidak dapat memodifikasiBakery class
(API eksternal, dll.) Maka Anda harus menggunakan pola Adaptor .Jika
bakery
tidak mengubah perilakunya secara dinamis dan Anda dapat memodifikasiBakery class
maka Anda harus memperluas antarmuka yang ada (seperti yang Anda usulkan pada awalnya) atau memperkenalkan antarmuka baruBrownieInterface
dan biarkanBakery
menerapkan dua antarmukaBakeryInterface
danBrownieInterface
.Kalau tidak, Anda akan menambah kompleksitas yang tidak perlu ke kode Anda (menggunakan pola Dekorator) tanpa alasan yang bagus!
sumber
Anda mengalami masalah ekspresi. Artikel ini oleh Stuart Sierra membahas solusi clojures, tetapi ia juga memberikan contoh di Jawa dan daftar solusi populer di OO klasik.
Ada juga presentasi oleh Chris Houser ini yang membahas dasar yang hampir sama.
sumber