Saya memiliki aplikasi yang mengambil integer sebagai input dan berdasarkan pada input panggilan metode statis dari berbagai kelas. Setiap kali nomor baru ditambahkan, kita perlu menambahkan case lain dan memanggil metode statis yang berbeda dari kelas yang berbeda. Sekarang ada 50 kasing di sakelar dan setiap kali saya perlu menambahkan kasing lain, saya bergidik. Apakah ada cara yang lebih baik untuk melakukan ini.
Saya melakukan beberapa pemikiran dan muncul dengan ide ini. Saya menggunakan pola strategi. Alih-alih memiliki saklar kasus, saya memiliki peta objek strategi dengan kuncinya adalah input integer. Setelah metode dipanggil, ia akan mencari objek dan memanggil metode generik untuk objek tersebut. Dengan cara ini saya dapat menghindari penggunaan konstruktor case switch.
Bagaimana menurut anda?
sumber
switch
kasing dan memanggil metode yang sudah ada sebelumnya di sistem kompleks Anda, atau Anda harus menemukan metode dan panggilannya?Jawaban:
Saya suka polimorfisme. Saya suka SOLID. Saya suka pemrograman berorientasi objek murni. Saya benci melihat ini diberikan perwakilan yang buruk karena mereka diterapkan secara dogmatis.
Anda belum membuat kasus yang baik untuk refactoring ke strategi. Omong-omong, refactoring memiliki nama. Ini disebut Ganti Bersyarat dengan Polimorfisme .
Saya telah menemukan beberapa saran untuk Anda dari c2.com :
Anda memiliki sakelar dengan 50 kasing dan alternatif Anda adalah menghasilkan 50 objek. Oh dan 50 baris kode konstruksi objek. Ini bukan kemajuan. Kenapa tidak? Karena refactoring ini tidak mengurangi jumlah dari 50. Anda menggunakan refactoring ini ketika Anda menemukan Anda perlu membuat pernyataan switch lain pada input yang sama di tempat lain. Saat itulah refactoring ini membantu karena mengubah 100 kembali menjadi 50.
Selama Anda mengacu pada "saklar" seperti itu satu-satunya yang Anda miliki, saya tidak merekomendasikan ini. Satu-satunya keuntungan yang didapat dari refactoring sekarang adalah mengurangi kemungkinan beberapa goofball akan menyalin dan menempelkan 50 case switch Anda.
Apa yang saya rekomendasikan adalah melihat dengan cermat pada 50 kasus ini untuk kesamaan yang dapat diperhitungkan. Maksud saya 50? Betulkah? Anda yakin perlu banyak kasus? Anda mungkin mencoba melakukan banyak hal di sini.
sumber
Peta objek strategi saja, yang diinisialisasi dalam beberapa fungsi kode Anda, tempat Anda memiliki beberapa baris kode
mengharuskan Anda dan kolega Anda untuk mengimplementasikan fungsi / strategi untuk dipanggil dalam kelas yang terpisah, dengan cara yang lebih seragam (karena objek strategi Anda semua harus mengimplementasikan antarmuka yang sama). Kode seperti itu seringkali sedikit lebih komprehensif daripada
Namun, itu masih tidak akan membebaskan Anda dari beban mengedit file kode ini setiap kali nomor baru perlu ditambahkan. Manfaat nyata dari pendekatan ini berbeda:
inisialisasi peta sekarang menjadi terpisah dari kode pengiriman yang sebenarnya memanggil fungsi yang terkait dengan nomor tertentu, dan yang terakhir tidak mengandung 50 pengulangan lagi, itu hanya akan terlihat seperti
myMap[number].DoIt(someParameters)
. Jadi kode pengiriman ini tidak perlu disentuh setiap kali nomor baru tiba dan dapat diimplementasikan sesuai dengan prinsip Terbuka-Tertutup. Selain itu, ketika Anda mendapatkan persyaratan di mana Anda perlu memperpanjang kode pengiriman itu sendiri, Anda tidak perlu mengubah 50 tempat lagi, tetapi hanya satu.konten peta ditentukan pada saat run-time (sementara konten konstruksi switch ditentukan sebelum waktu kompilasi), jadi ini memberi Anda kesempatan untuk membuat logika inisialisasi lebih fleksibel atau dapat diperluas.
Jadi ya, ada beberapa manfaat, dan ini jelas merupakan langkah menuju kode yang lebih SOLID. Namun, jika itu terbayar untuk refactor, adalah sesuatu yang Anda atau tim Anda harus putuskan sendiri. Jika Anda tidak mengharapkan kode pengiriman diubah, logika inisialisasi diubah, dan keterbacaan
switch
bukan masalah nyata, maka refactoring Anda mungkin tidak begitu penting sekarang.sumber
Doit1
,Doit2
dll dengan satuDoit
metode yang memiliki banyak implementasi yang berbeda.doTheThing()
metode simbol input. Maka Anda tidak perlu mempertahankan peta.Saya sangat mendukung strategi yang dijabarkan dalam jawaban oleh @DocBrown .
Saya akan menyarankan peningkatan jawaban.
Panggilan
dapat didistribusikan. Anda tidak harus kembali ke file yang sama untuk menambahkan strategi lain, yang menganut prinsip Open-Closed lebih baik.
Katakanlah Anda menerapkan
Strategy1
dalam file Strategy1.cpp. Anda dapat memiliki blok kode berikut di dalamnya.Anda dapat mengulangi kode yang sama di setiap file StategyN.cpp. Seperti yang Anda lihat, itu akan menjadi banyak kode berulang. Untuk mengurangi duplikasi kode, Anda bisa menggunakan templat yang bisa dimasukkan ke dalam file yang dapat diakses oleh semua
Strategy
kelas.Setelah itu, satu-satunya hal yang harus Anda gunakan di Strategy1.cpp adalah:
Baris yang sesuai di StrategyN.cpp adalah:
Anda bisa menggunakan templat ke level lain dengan menggunakan templat kelas untuk kelas Strategi konkret.
Dan kemudian, alih-alih
Strategy1
, gunakanConcreteStrategy<1>
.Ubah kelas pembantu untuk mendaftar
Strategy
menjadi:Ubah kode di Strateg1.cpp ke:
Ubah kode di StrategN.cpp ke:
sumber