Keuntungan dari Pola Strategi

15

Mengapa bermanfaat untuk menggunakan pola strategi jika Anda bisa menulis kode Anda dalam kasus if / then?

Sebagai contoh: Saya memiliki kelas Wajib Pajak, dan salah satu metode menghitung pajak menggunakan algoritma yang berbeda. Jadi mengapa tidak dapat memiliki jika / kemudian case dan mencari tahu algoritma apa yang digunakan dalam metode itu, daripada menggunakan pola strategi? Juga, mengapa Anda tidak bisa menerapkan metode terpisah untuk setiap algoritma di kelas Wajib Pajak?

Juga, apa artinya bagi algoritma untuk berubah saat runtime?

Armon Safai
sumber
2
Apakah ini pekerjaan rumah? Lebih baik menyatakan itu di muka jika demikian.
Fuhrmanator
2
@Fuhrmanator tidak bukan
Armon Safai

Jawaban:

20

Untuk satu hal, gumpalan besar if/elsebalok tidak mudah diuji . Setiap "cabang" baru menambahkan jalur eksekusi lain dan dengan demikian meningkatkan kompleksitas siklomatik . Jika Anda ingin menguji kode Anda secara menyeluruh, Anda harus mencakup semua jalur eksekusi, dan setiap kondisi akan mengharuskan Anda untuk menulis setidaknya satu tes lagi (dengan asumsi Anda menulis tes kecil, fokus). Di sisi lain, kelas yang menerapkan strategi biasanya mengekspos hanya 1 metode publik, yang mudah untuk diuji.

Jadi, dengan bersarang if/elseAnda akan berakhir dengan banyak tes untuk satu bagian dari kode Anda, sementara dengan Strategi Anda akan memiliki beberapa tes untuk masing-masing dari beberapa strategi sederhana. Dengan yang terakhir, mudah untuk memiliki cakupan yang lebih baik, karena lebih sulit untuk kehilangan jalur eksekusi.

Adapun ekstensibilitas , bayangkan Anda sedang menulis kerangka kerja, di mana pengguna seharusnya bisa menyuntikkan perilaku mereka sendiri. Misalnya, Anda ingin membuat semacam kerangka perhitungan pajak, dan ingin mendukung sistem pajak di berbagai negara. Alih-alih menerapkan semuanya, Anda hanya ingin memberikan kesempatan kepada pengguna kerangka untuk memberikan implementasi tentang cara menghitung beberapa pajak tertentu.

Inilah pola strateginya:

  • Anda mendefinisikan antarmuka, misalnya TaxCalculation, dan kerangka kerja Anda menerima contoh jenis ini untuk menghitung pajak
  • Pengguna kerangka kerja membuat kelas yang mengimplementasikan antarmuka ini dan meneruskannya ke kerangka kerja Anda, sehingga memberikan cara untuk melakukan beberapa bagian perhitungan

Anda tidak dapat melakukan hal yang sama dengan if/else, karena itu akan membutuhkan perubahan kode kerangka kerja, dalam hal ini tidak akan menjadi kerangka kerja lagi. Karena kerangka kerja sering didistribusikan dalam bentuk yang dikompilasi, ini mungkin satu-satunya pilihan.

Namun, bahkan jika Anda hanya menulis beberapa kode biasa, Strategi bermanfaat karena membuat maksud Anda lebih jelas. Ia mengatakan "logika ini pluggable dan bersyarat", yaitu ada beberapa implementasi yang dapat bervariasi tergantung pada tindakan pengguna, konfigurasi, atau bahkan platform.

Menggunakan pola Strategi dapat meningkatkan keterbacaan karena, sementara kelas yang mengimplementasikan beberapa strategi tertentu biasanya harus memiliki nama deskriptif, misalnya USAIncomeTaxCalculator, if/elseblok "tanpa nama", dalam kasus terbaik hanya berkomentar, dan komentar dapat berbohong. Juga, dari selera pribadi saya, hanya memiliki lebih dari 3 if/elseblok berturut-turut tidak dapat dibaca, dan menjadi sangat buruk dengan blok bersarang.

Prinsip Terbuka / Tertutup juga sangat relevan, karena, seperti yang saya jelaskan dalam contoh di atas, Strategi memungkinkan Anda untuk memperluas logika di beberapa bagian kode Anda ("terbuka untuk ekstensi") tanpa menulis ulang bagian-bagian itu ("ditutup untuk modifikasi" ).

skrip
sumber
1
if/elseblok juga menurunkan keterbacaan kode. Adapun pola strategi, prinsip Terbuka / Tertutup layak disebut IMO.
Maciej Chałapuk
1
Testabilitas adalah alasan utama. (Sebagian besar) Setiap cabang dalam kode Anda harus diuji. Semakin banyak ifyang Anda miliki, semakin banyak jalur yang mungkin ada melalui kode Anda, semakin banyak tes yang harus Anda tulis dan lebih banyak cara agar metode itu gagal. Jika saya dapat mengutip almarhum Yogi Berra: "Jika Anda datang ke persimpangan jalan, ambillah." Ini berlaku cemerlang untuk pengujian unit. Selain itu, banyak ifpernyataan berarti Anda cenderung mengulangi logika untuk kondisi tersebut, semakin meningkatkan beban pengujian Anda dan meningkatkan risiko bug muncul.
Greg Burghardt
Terima kasih atas jawabannya. Jadi mengapa saya tidak dapat menggunakan metode terpisah untuk algoritma yang berbeda di kelas yang sama?
Armon Safai
Anda bisa, tetapi Anda masih membutuhkan banyak if/elseblok untuk memanggil mereka (atau di dalamnya, untuk menentukan apakah harus melakukan sesuatu atau tidak), jadi itu tidak banyak membantu, kecuali mungkin kode yang lebih mudah dibaca. Dan juga tidak ada ekstensibilitas bagi pengguna kerangka kerja hipotetis Anda saat itu.
scriptin
1
Bisakah Anda lebih jelas tentang mengapa lebih mudah untuk diuji? Contoh untuk refactoring pernyataan kasus (atau jika / kemudian) ke metode polimorfik (dasar untuk strategi) cukup mudah untuk diuji. refactoring.com/catalog/replaceConditionalWithPolymorphism.html Jika saya tahu semua syarat untuk diuji, saya menulis tes untuk masing-masing. Jika saya memiliki strategi, saya harus instantiate dan menjalankan satu untuk masing-masing. Bagaimana pendekatan strategi lebih mudah untuk diuji? Kita tidak berbicara tentang ifs kompleks yang bersarang ketika Anda refactor terhadap strategi.
Fuhrmanator
5

Mengapa bermanfaat untuk menggunakan pola strategi jika Anda bisa menulis kode Anda dalam kasus if / then?

Terkadang Anda hanya perlu menggunakan if / then. Ini adalah kode sederhana yang mudah dibaca.

Dua masalah utama dengan kode if / then sederhana adalah bahwa hal itu dapat melanggar prinsip tertutup terbuka . Jika Anda harus masuk dan menambahkan atau mengubah suatu kondisi, Anda memodifikasi kode ini. Jika Anda berharap memiliki lebih banyak kondisi, hanya menambahkan strategi baru lebih sederhana / lebih bersih / lebih kecil kemungkinannya untuk dipatahkan.

Masalah lainnya adalah kopling. Dengan menggunakan if / then, semua implementasi terkait dengan implementasi itu, membuat mereka lebih sulit untuk berubah di masa depan. Dengan menggunakan strategi, satu-satunya sambungan adalah antarmuka dari strategi.

Telastyn
sumber
apa yang salah dengan memodifikasi kode dalam kode if / then? tidakkah Anda harus memodifikasi kode dalam pola strategi juga jika Anda memutuskan untuk mengubah bagaimana salah satu algoritma berfungsi?
Armon Safai
@armonsafai - jika Anda memodifikasi strategi, Anda hanya perlu menguji strategi tersebut. Jika Anda memodifikasi semua algoritme, Anda perlu menguji semua algoritme. Lebih buruk lagi, jika Anda menambahkan strategi baru, Anda hanya perlu menguji strategi tersebut. Jika Anda menambahkan kondisional baru, Anda perlu menguji semua kondisional.
Telastyn
4

Strategi berguna ketika if/thenkondisi didasarkan pada jenis , seperti dijelaskan dalam http://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html

Pengecekan tipe-ketik biasanya tidak memiliki kompleksitas siklomatik yang tinggi, jadi saya tidak akan mengatakan bahwa Strategi meningkatkan segalanya di sana.

Alasan utama Strategi dijelaskan dalam buku GoF hal.316 yang memperkenalkan pola:

Gunakan pola Strategi saat

...

  • kelas mendefinisikan banyak perilaku, dan ini muncul sebagai beberapa pernyataan kondisional dalam operasinya. Alih-alih banyak kondisional, pindahkan cabang kondisional terkait ke kelas Strategi mereka sendiri.

Sebagaimana disebutkan dalam jawaban lain, jika diterapkan dengan tepat, pola Strategi memungkinkan penambahan ekstensi baru (strategi konkret) tanpa perlu memerlukan modifikasi dari sisa kode. Inilah yang disebut prinsip Terbuka-Tertutup atau prinsip Variasi yang Dilindungi . Tentu saja, Anda masih harus membuat kode strategi konkret baru, dan kode klien harus mengenali strategi sebagai plug-in (ini bukan hal sepele).

Dengan if/thenconditional, perlu untuk mengubah kode kelas yang berisi logika kondisional. Seperti disebutkan dalam jawaban lain, terkadang ini OK jika Anda tidak ingin menambahkan kompleksitas untuk mendukung penambahan fungsionalitas baru (plug-in) tanpa kompilasi ulang.

Fuhrmanator
sumber
3

[...] jika Anda hanya dapat menulis kode jika / maka case?

Itulah manfaat terbesar dari pola strategis. Tidak memiliki kondisi.

Anda ingin kelas / metode / fungsi Anda sesederhana dan sesingkat mungkin. Kode pendek sangat mudah diuji dan sangat mudah dibaca.

Kondisi ( if/ elseif/ else) membuat kelas / metode / fungsi Anda lama, karena biasanya kode tempat satu keputusan dievaluasi trueberbeda dari bagian di mana keputusan itu dievaluasi false.


Manfaat besar lain dari pola strategi adalah, dapat digunakan kembali di seluruh proyek Anda.

Saat menggunakan pola desain strategi, Anda sangat mungkin memiliki semacam wadah IoC, dari mana Anda memperoleh implementasi antarmuka yang diinginkan, mungkin dengan getById(int id)metode, di mana idbisa menjadi anggota enumerator.

Ini berarti, pembuatan implementasi hanya di satu tempat kode Anda.

Jika Anda ingin menambahkan lebih banyak implementasi, Anda menambahkan implementasi baru ke getByIdmetode dan perubahan ini tercermin di mana-mana dalam kode tempat Anda menyebutnya.

Dengan if/ elseif/ elseini tidak mungkin dilakukan. Dengan menambahkan implementasi baru, Anda harus menambahkan elseifblok baru dan melakukannya di mana saja di mana implementasi digunakan, atau Anda mungkin berakhir dengan kode yang tidak valid, karena Anda lupa menambahkan implementasi ke strukturnya.


Juga, apa artinya bagi algoritma untuk berubah saat runtime?

Dalam contoh saya, idbisa berupa variabel yang diisi berdasarkan input pengguna. Jika pengguna mengklik tombol A, maka id = 2, jika dia mengklik tombol B, maka id = 8.

Karena nilai yang berbeda id, implementasi antarmuka yang berbeda diperoleh dari wadah IoC dan kode melakukan operasi yang berbeda.

Andy
sumber
Terima kasih atas jawabannya. Jadi mengapa saya tidak dapat menggunakan metode terpisah untuk algoritma yang berbeda di kelas yang sama?
Armon Safai
@ArmonSafai Akankah metode terpisah benar-benar menyelesaikan apa pun? Saya kira tidak. Anda memindahkan masalah dari satu tempat ke tempat lain, dan keputusan metode mana yang akan dihubungi berdasarkan hasil dari suatu kondisi. Sekali lagi, sebuah if/ elseif/ elsenegara. Sama seperti sebelumnya, hanya di tempat yang berbeda.
Andy
Jadi kasus if / then akan menjadi hak utama? Bukankah Anda harus menggunakan if / then case in main untuk pola strategi juga?
Armon Safai
1
@ArmonSafai Tidak, Anda tidak akan melakukannya. Anda akan memiliki saklar pada idvariabel dalam getByIdmetode ini, yang akan mengembalikan implementasi spesifik. Setiap kali Anda membutuhkan implementasi antarmuka, Anda akan meminta wadah IoC untuk mengirimkannya kepada Anda.
Andy
1
@ArmonSafai Anda bisa saja memiliki metode getSortByEnumType(SortEnum type)mengembalikan implementasi Sortantarmuka, memiliki metode getSortTypemengembalikan SortEnumvariabel dan mengambil koleksi sebagai parameter, dan getSortByEnumTypemetode itu lagi akan berisi saklar pada typeparameter mengembalikan Anda algoritma pengurutan yang benar. Jika Anda perlu menambahkan algoritma pengurutan baru, Anda hanya perlu mengedit metode enum dan satu. Dan Anda sudah siap.
Andy
2

Mengapa bermanfaat untuk menggunakan pola strategi jika Anda bisa menulis kode Anda dalam kasus if / then?

Pola Strategi memungkinkan Anda memisahkan algoritma (detail) dari logika bisnis Anda (kebijakan tingkat tinggi). Kedua hal ini tidak hanya membingungkan untuk dibaca ketika dicampur, tetapi juga memiliki alasan yang sangat berbeda untuk berubah.

Ada juga faktor skalabilitas kerja tim utama di sini. Bayangkan sebuah tim pemrograman besar di mana banyak orang mengerjakan paket akuntansi ini. Jika algoritme pajak semuanya ada dalam kelas atau modul Wajib Pajak , maka kemungkinan menggabungkan konflik. Menggabungkan konflik memakan waktu dan mudah diselesaikan. Kali ini menguras produktivitas dari tim dan kesalahan yang diperkenalkan oleh kredibilitas buruk merusak kredibilitas dengan pelanggan.

Juga, apa artinya bagi algoritma untuk berubah saat runtime?

Algoritma yang berubah saat runtime adalah yang perilakunya ditentukan oleh konfigurasi atau konteks. Pendekatan if / then di tempat tidak secara efektif mengaktifkan ini karena melibatkan memuat kembali kelas yang digunakan aktif. Dengan Pola Strategi, objek strategi yang mengimplementasikan setiap algoritma dapat dibangun pada penggunaan. Akibatnya perubahan pada algoritma ini (perbaikan bug atau peningkatan) dapat dilakukan dan dimuat kembali saat runtime. Pendekatan ini dapat digunakan untuk memungkinkan ketersediaan terus-menerus dan rilis tanpa downtime.

Alain O'Dea
sumber
1

Tidak ada yang salah dengan if/elseper se. Dalam banyak kasus if/elseadalah cara mengekspresikan logika yang paling sederhana dan paling mudah dibaca. Jadi pendekatan yang Anda gambarkan sangat valid dalam banyak kasus. (Ini juga sangat dapat diuji, sehingga tidak menjadi masalah.)

Tetapi ada beberapa kasus tertentu di mana pola strategi dapat meningkatkan pemeliharaan kode keseluruhan. Sebagai contoh:

  • Jika algoritma perhitungan pajak tertentu dapat berubah secara independen satu sama lain dan dari logika inti. Dalam hal ini alangkah baiknya jika mereka dipisahkan ke dalam kelas yang berbeda, karena perubahan akan dilokalkan.
  • Jika algoritma baru dapat ditambahkan di masa depan, tanpa inti logika berubah.
  • Jika penyebab perbedaan antara kedua algoritma juga mempengaruhi bagian lain dari kode. Katakanlah Anda memilih antara kedua algoritma berdasarkan braket pendapatan dari wajib pajak. Jika braket pendapatan ini juga menyebabkan Anda memilih cabang berbeda tempat-tempat lain dalam kode, maka lebih baik untuk instantiate strategi yang sesuai dengan braket pendapatan satu kali, dan menelepon saat diperlukan, daripada memiliki beberapa jika / jika-cabang tersebar di kode.

Agar pola strategi masuk akal, antarmuka antara logika inti dan algoritma penghitungan pajak harus lebih stabil daripada komponen individual. Jika ada kemungkinan bahwa perubahan persyaratan akan menyebabkan antarmuka berubah, maka pola strategi sebenarnya bisa menjadi kewajiban.

Itu semua bermuara jika "algoritma perhitungan pajak" dapat dipisahkan dengan bersih dari logika inti yang memanggilnya. Pola strategi memiliki beberapa overhead dibandingkan dengan if/else, jadi Anda harus memutuskan berdasarkan kasus per kasus jika investasi itu sepadan.

JacquesB
sumber