Bagaimana cara saya menghindari menulis banyak fungsi pass-through dalam bungkus?

13

Saya memiliki kelas, yang membungkus kelas lain dari jenis basis umum. Karena antarmuka tipe dasar cukup besar, ini melibatkan penulisan banyak fungsi pass-through. Saya mencari cara untuk menghindari ini.

Mari kita buat contoh:

      Car
     /   \
Volvo     VolvoWithTrailer

Sekarang saya harus mengimplementasikan masing-masing dan setiap fungsi di antarmuka mobil untuk VolvoWithTrailer dan memanggil fungsi yang sesuai pada objek Volvo yang dibungkus kecuali mungkin GetMaxSpeed ​​() yang akan mengembalikan sesuatu yang lebih rendah. Pada dasarnya saya akan memiliki banyak fungsi seperti

int VolvoWithTrailer::GetNumSeats() {
  return mVolvo.GetNumSeats()
}

Cara yang jelas untuk menyelesaikan ini adalah menjadikan VolvoWithTrailer sebagai subkelas Volvo

    Car
     |
   Volvo
     |
VolvoWithTrailer

tetapi itu tampaknya melanggar prinsip mendukung komposisi daripada warisan.

Bagaimana lagi saya bisa menghindari menulis semua pembungkus itu (bahasanya adalah C ++)? Atau - jika itu posisi Anda - mengapa saya harus menulisnya / hanya menggunakan warisan? Apakah ada keajaiban templat yang dapat membantu dengan ini?

Sarien
sumber
2
Belum terlalu berlebihan, dan berpikir di Jawa. Bagaimana dengan antarmuka 'Trailer'? VolvoWithTrailer akan memperluas Volvo dan mengimplementasikan antarmuka Trailer?
7
Lebih menyukai komposisi daripada warisan hanya jika masuk akal untuk melakukannya.
Robert Harvey
@RobertHarvey: +1. Itu adalah pedoman, bukan "prinsip," dan tentu saja bukan perintah yang absolut.
Mason Wheeler
Dalam Python Anda dapat menyelesaikan ini dengan introspeksi (apa yang C # sebut refleksi).
user16764
1
Bukankah IDE Anda menangani pembuatan kode?
Amy Blankenship

Jawaban:

5

Pendapat saya adalah bahwa Anda harus menulis apa pun yang Anda perlu tulis untuk membuat stabilitas jangka panjang dan pemeliharaan program lebih baik. Apa gunanya menghindari menulis 20 baris kode hari ini, jika setiap kali Anda menyentuh sesuatu yang menggunakan kode ini atau kembali untuk mempertahankan Kelas ini, Anda perlu tambahan 5 menit atau lebih karena Anda tidak memasukkan waktu hari ini?

Jadi pertanyaannya kemudian menjadi "apa yang perlu Anda tulis?" Saya tidak berpikir Anda memberikan informasi yang cukup untuk dapat memberikan jawaban yang pasti, jadi saya hanya akan membuat daftar beberapa hal yang akan saya pikirkan dalam membuat keputusan:

1. Apakah Anda perlu memiliki objek Trailer sendiri, sekarang atau di masa mendatang?
Jika demikian, Anda memiliki argumen yang cukup bagus untuk membuat pembungkus di sekitar kedua objek yang dikomposisikan, karena Anda sudah harus membungkus satu atau yang lain. Mungkin juga konsisten.

2. Apakah ada di antara tiga jenis (Mobil, Trailer, CarWithTrailer) di area kode yang sering dikunjungi pengembang atau terlihat mungkin?
Jika demikian, berhati-hatilah, karena konsekuensi memilih hal yang salah dapat sangat mahal diamortisasi setiap kali kode disentuh. Jika tidak, mungkin tidak ada bedanya dengan apa yang Anda putuskan. Pilih saja arah dan ikuti saja.

3. Apa yang paling mudah dipahami?
Apakah satu pendekatan melompat pada Anda bahwa seseorang yang datang di belakang Anda akan segera "mendapatkan" apa yang Anda coba lakukan? Apakah rekan satu tim Anda memiliki bias tertentu yang mungkin membuat satu pendekatan lebih sulit untuk dipertahankan? Jika semua hal sama, pilih solusi yang memaksakan beban kognitif terendah.

4. Apakah ada manfaat tambahan untuk menggunakan satu pendekatan di atas yang lain?
Satu hal yang melompat keluar pada saya adalah bahwa gagasan pembungkus memiliki keunggulan yang berbeda jika Anda menulis bahwa CarWithTrailerWrapper Anda dapat membungkus setiap mobil dan setiap cuplikan ke CarWithTrailer a. Kemudian, Anda akhirnya menulis semua metode pass-through Anda, tetapi Anda hanya menulisnya sekali , bukan satu kali untuk setiap Kelas Mobil.

Ini membuat investasi awal Anda dalam menulis metode pass-through jauh lebih murah saat Anda menambahkan lebih banyak Mobil dan Trailer. Ini juga membantu mengurangi godaan untuk memasangkan banyak hal secara langsung ke Volvo atau VolvoWithTrailer, sambil mengurangi konsekuensi dari pemasangan ke CarWithTrailerWrapper, karena Anda dapat melakukan lebih banyak hal hanya dengan satu implementasi.

Mungkin ada keuntungan berbeda yang akan Anda dapatkan secara gratis dengan menggunakan metode ekstensi, tetapi saya tidak melihatnya.

OK, jadi sepertinya saya sudah bicara banyak tentang untuk terus maju dan mengisi metode pass-through, untuk aplikasi non-sepele.

Saya bukan programmer C ++, jadi saya tidak tahu alat pembuat kode apa yang tersedia untuk Anda. IDE yang saya gunakan dapat menghasilkan metode dari Antarmuka, dan saya bisa menambahkan templat kode yang akan membuat penulisan pass-through tidak menimbulkan rasa sakit. Jika Anda tidak memiliki akses ke IDE yang melakukan ini, Anda sebenarnya bisa membiarkan Excel menulis kode untuk Anda .

Amy Blankenship
sumber
3

Karena antarmuka tipe dasar cukup besar, ini melibatkan penulisan banyak fungsi pass-through.

Dan ini masalahnya.

Antarmuka harus menangani satu tanggung jawab saja. Menjaga mereka tetap tipis dan fokus membatasi jumlah pekerjaan passthrough yang mungkin perlu Anda lakukan jika ada dekorator, proksi, atau pembungkus lainnya (selain membuat kelas menyederhanakan untuk menggunakan, menguji, memelihara, dan memperluas).

Telastyn
sumber
5
Uh, apa? Satu Kelas dapat mengimplementasikan banyak antarmuka, dan antarmuka dapat mewarisi dari satu sama lain. Jadi, bahkan jika sebuah Antarmuka cukup kecil, itu tidak ada hubungannya dengan apakah Kelas yang mengimplementasikannya akan membutuhkan banyak fungsi atau fungsi pass-through. Semakin kecil dan lebih jelas kelas - kelasnya , semakin besar kemungkinan Anda akan membutuhkan fungsi pass-through.
Amy Blankenship