Pola Strategi berfungsi dengan baik untuk menghindari besar jika ... konstruksi yang lain dan membuatnya lebih mudah untuk menambah atau mengganti fungsi. Namun, menurut saya masih ada satu kekurangan. Sepertinya dalam setiap implementasi masih perlu ada konstruksi percabangan. Mungkin pabrik atau file data. Sebagai contoh, ambil sistem pemesanan.
Pabrik:
// All of these classes implement OrderStrategy
switch (orderType) {
case NEW_ORDER: return new NewOrder();
case CANCELLATION: return new Cancellation();
case RETURN: return new Return();
}
Kode setelah ini tidak perlu khawatir, dan sekarang hanya ada satu tempat untuk menambahkan jenis pesanan baru, tetapi bagian kode ini masih tidak dapat diperluas. Menariknya ke dalam file data agak membantu keterbacaan (masih bisa diperdebatkan, saya tahu):
<strategies>
<order type="NEW_ORDER">com.company.NewOrder</order>
<order type="CANCELLATION">com.company.Cancellation</order>
<order type="RETURN">com.company.Return</order>
</strategies>
Tapi ini masih menambahkan kode boilerplate untuk memproses file data - diberikan, lebih mudah diuji unit dan kode yang relatif stabil, tetapi kompleksitas tambahan nontheless.
Juga, konstruksi semacam ini tidak menguji integrasi dengan baik. Setiap strategi individu mungkin lebih mudah untuk diuji sekarang, tetapi setiap strategi baru yang Anda tambahkan adalah kompleksitas tambahan untuk diuji. Ini kurang dari yang Anda miliki jika Anda tidak menggunakan pola, tetapi masih ada.
Apakah ada cara untuk menerapkan pola strategi yang mengurangi kompleksitas ini? Atau apakah ini sesederhana mungkin, dan mencoba melangkah lebih jauh hanya akan menambah lapisan abstraksi untuk sedikit atau tanpa manfaat?
sumber
eval
... mungkin tidak berfungsi di Jawa tapi mungkin dalam bahasa lain?Jawaban:
Tentu saja tidak. Bahkan jika Anda menggunakan wadah IoC, Anda harus memiliki kondisi di suatu tempat, memutuskan implementasi konkret yang akan disuntikkan. Ini adalah sifat dari pola Strategi.
Saya tidak benar-benar mengerti mengapa orang berpikir ini masalah. Ada pernyataan di beberapa buku, seperti Fowler's Refactoring , bahwa jika Anda melihat sakelar / kasing atau rantai if / elses di tengah kode lain, Anda harus mempertimbangkannya sebagai aroma dan ingin memindahkannya ke metodenya sendiri. Jika kode dalam setiap kasus lebih dari satu baris, mungkin dua, maka Anda harus mempertimbangkan menjadikan metode itu sebagai Metode Pabrik, mengembalikan Strategi.
Beberapa orang menganggap ini sebagai saklar / case buruk. Ini bukan kasusnya. Tapi itu harus berada pada dirinya sendiri, jika memungkinkan.
sumber
Ya , dengan menggunakan hashmap / kamus tempat setiap implementasi Strategi mendaftar. Metode pabrik akan menjadi seperti itu
Setiap implementasi strategi harus mendaftarkan pabrik dengan Tipe pemesanan dan beberapa informasi cara membuat kelas.
Anda dapat menggunakan konstruktor statis untuk pendaftaran, jika bahasa Anda mendukung ini.
Metode register tidak lebih dari menambahkan nilai baru ke hashmap:
[update 2012-05-04]
Solusi ini jauh lebih kompleks daripada "solusi peralihan" asli yang paling saya sukai.
Namun dalam lingkungan di mana strategi sering berubah (mis. Perhitungan harga tergantung pada pelanggan, waktu, ....) solusi hashmap ini dikombinasikan dengan IoC-Container bisa menjadi solusi yang baik.
sumber
factory.register(NEW_ORDER, NewOrder.class);
pembersih, atau kurang pelanggaran OCP, daripada bariscase NEW_ORDER: return new NewOrder();
?"Strategi" adalah tentang harus memilih antara algoritma alternatif setidaknya sekali , tidak kurang. Di suatu tempat di program Anda seseorang harus membuat keputusan - mungkin pengguna atau program Anda. Jika Anda menggunakan IoC, refleksi, evaluator datafile atau konstruksi switch / kasus untuk menerapkan ini tidak mengubah situasi.
sumber
Pola strategi digunakan ketika Anda menentukan perilaku yang mungkin dan paling baik digunakan ketika menunjuk pawang pada saat startup. Menentukan contoh strategi yang digunakan dapat dilakukan melalui Mediator, wadah IoC standar Anda, beberapa Pabrik seperti yang Anda gambarkan, atau hanya dengan menggunakan yang tepat berdasarkan konteks (karena seringkali, strategi tersebut dipasok sebagai bagian dari penggunaan yang lebih luas dari kelas yang memuatnya).
Untuk perilaku semacam ini di mana metode yang berbeda perlu dipanggil berdasarkan data, maka saya sarankan menggunakan konstruksi polimorfisme yang disediakan oleh bahasa yang ada; bukan pola strategi.
sumber
Dalam berbicara dengan pengembang lain tempat saya bekerja, saya menemukan solusi lain yang menarik - khusus untuk Java, tapi saya yakin idenya bekerja dalam bahasa lain. Buat enum (atau peta, tidak masalah yang mana) menggunakan referensi kelas dan instantiate menggunakan refleksi.
Ini secara drastis mengurangi kode pabrik:
(Harap abaikan penanganan kesalahan yang buruk - contoh kode :))
Ini bukan yang paling fleksibel, karena build masih diperlukan ... tetapi mengurangi perubahan kode menjadi satu baris. Saya suka bahwa data dipisahkan dari kode pabrik. Anda bahkan dapat melakukan hal-hal seperti mengatur parameter dengan menggunakan kelas / antarmuka abstrak untuk menyediakan metode umum atau membuat anotasi waktu kompilasi untuk memaksa tanda tangan konstruktor tertentu.
sumber
Ekstensibilitas dapat ditingkatkan dengan meminta setiap kelas menentukan jenis pesanannya sendiri. Lalu pabrik Anda memilih yang cocok.
Sebagai contoh:
sumber
Saya pikir harus ada batasan pada berapa banyak cabang yang dapat diterima.
Misalnya, jika saya memiliki lebih dari delapan kasus di dalam pernyataan switch saya, maka saya mengevaluasi kembali kode saya dan mencari apa yang dapat saya faktor ulang. Cukup sering saya menemukan bahwa kasus-kasus tertentu dapat dikelompokkan menjadi pabrik yang terpisah. Asumsi saya di sini adalah ada pabrik yang membangun strategi.
Bagaimanapun, Anda tidak dapat menghindari ini dan di suatu tempat Anda harus memeriksa keadaan atau jenis objek yang Anda kerjakan. Anda kemudian akan membangun strategi untuk itu. Pemisahan keprihatinan yang lama.
sumber