Saya akan menghemat beberapa payload string dalam database. Saya memiliki dua konfigurasi global:
- enkripsi
- kompresi
Ini dapat diaktifkan atau dinonaktifkan menggunakan konfigurasi sedemikian rupa sehingga hanya salah satu dari mereka yang diaktifkan, keduanya diaktifkan atau keduanya dinonaktifkan.
Implementasi saya saat ini adalah ini:
if (encryptionEnable && !compressEnable) {
encrypt(data);
} else if (!encryptionEnable && compressEnable) {
compress(data);
} else if (encryptionEnable && compressEnable) {
encrypt(compress(data));
} else {
data;
}
Saya sedang berpikir tentang pola Dekorator. Apakah ini pilihan yang tepat, atau mungkin ada alternatif yang lebih baik?
design
design-patterns
object-oriented-design
refactoring
Damith Ganegoda
sumber
sumber
if
pernyataan baru ?Jawaban:
Saat mendesain kode, Anda selalu memiliki dua opsi.
Saya tidak akan fokus pada yang pertama dari keduanya, karena benar-benar tidak ada yang bisa dikatakan. Jika Anda hanya ingin membuatnya berfungsi, Anda bisa membiarkan kode apa adanya.
Tetapi apa yang akan terjadi, jika Anda memilih untuk melakukannya dengan cara yang sangat bagus dan benar-benar menyelesaikan masalah dengan pola desain, seperti yang Anda inginkan?
Anda bisa melihat proses berikut:
Saat merancang kode OO, sebagian besar
if
yang ada dalam kode tidak harus ada di sana. Secara alami, jika Anda ingin membandingkan dua tipe skalar, sepertiint
s ataufloat
s, Anda cenderung memilikiif
, tetapi jika Anda ingin mengubah prosedur berdasarkan konfigurasi, Anda dapat menggunakan polimorfisme untuk mencapai apa yang Anda inginkan, pindahkan keputusan (if
s) dari logika bisnis Anda ke suatu tempat, di mana objek dipakai - ke pabrik .Sampai sekarang, proses Anda dapat melewati 4 jalur terpisah:
data
tidak dienkripsi atau dikompresi (tidak memanggil apa pun, kembalidata
)data
dikompresi (panggilcompress(data)
dan kembalikan)data
dienkripsi (panggilencrypt(data)
dan kembalikan)data
dikompresi dan dienkripsi (panggilanencrypt(compress(data))
dan kembalikan)Hanya dengan melihat 4 jalur, Anda menemukan masalah.
Anda memiliki satu proses yang memanggil 3 (secara teoritis 4, jika Anda menghitung tidak memanggil apa pun sebagai satu) metode berbeda yang memanipulasi data dan kemudian mengembalikannya. Metode memiliki nama yang berbeda , berbeda disebut API publik (cara di mana metode mengkomunikasikan perilaku mereka).
Dengan menggunakan pola adaptor , kita dapat memecahkan masalah colision nama (kita dapat menyatukan API publik) yang telah terjadi. Sederhananya, adaptor membantu dua antarmuka yang tidak kompatibel bekerja bersama. Juga, adaptor bekerja dengan mendefinisikan antarmuka adaptor baru, yang mana kelas mencoba menyatukan implementasi API mereka.
Saya akan berasumsi, bahwa saat ini Anda dapat memiliki dua kelas yang bertanggung jawab untuk kompresi dan enkripsi.
Dalam dunia perusahaan, bahkan kelas-kelas khusus ini sangat mungkin akan diganti oleh antarmuka, seperti
class
kata kunci yang akan digantiinterface
(jika Anda berurusan dengan bahasa seperti C #, Java dan / atau PHP) atauclass
kata kunci akan tetap ada, tetapiCompress
danEncrypt
metode akan didefinisikan sebagai virtual murni , jika Anda kode dalam C ++.Untuk membuat adaptor, kami mendefinisikan antarmuka umum.
Kemudian kita harus menyediakan implementasi antarmuka agar bermanfaat.
Dengan melakukan ini, Anda berakhir dengan 4 kelas, masing-masing melakukan sesuatu yang sama sekali berbeda, tetapi masing-masing dari mereka menyediakan API publik yang sama. The
Process
Metode.Dalam logika bisnis Anda, di mana Anda berurusan dengan keputusan tidak ada / enkripsi / kompresi / keduanya, Anda akan merancang objek Anda untuk membuatnya tergantung pada
DataProcessing
antarmuka yang kami desain sebelumnya.Prosesnya sendiri bisa sesederhana ini:
Tidak ada lagi persyaratan. Kelas
DataService
tidak tahu apa yang akan dilakukan dengan data ketika diberikan kepadadataProcessing
anggota, dan tidak terlalu peduli tentang itu, itu bukan tanggung jawabnya.Idealnya, Anda akan memiliki unit test yang menguji 4 kelas adaptor yang Anda buat untuk memastikan mereka bekerja, Anda membuat test pass Anda. Dan jika mereka lulus, Anda bisa yakin mereka akan bekerja di mana pun Anda memanggilnya dalam kode Anda.
Jadi melakukannya dengan cara ini saya tidak akan pernah memiliki
if
kode lagi?Tidak. Anda cenderung memiliki persyaratan dalam logika bisnis Anda, tetapi mereka masih harus berada di suatu tempat. Tempat itu adalah pabrikmu.
Dan ini bagus. Anda memisahkan masalah penciptaan dan benar-benar menggunakan kode. Jika Anda membuat pabrik Anda dapat diandalkan (di Jawa Anda bahkan bisa menggunakan sesuatu seperti kerangka kerja Guice oleh Google), dalam logika bisnis Anda, Anda tidak khawatir memilih kelas yang tepat untuk disuntikkan. Karena Anda tahu pabrik Anda berfungsi dan akan memberikan apa yang diminta.
Apakah perlu untuk memiliki semua kelas, antarmuka, dll?
Ini membawa kita kembali ke awal.
Dalam OOP, jika Anda memilih jalur untuk menggunakan polimorfisme, benar-benar ingin menggunakan pola desain, ingin mengeksploitasi fitur-fitur bahasa dan / atau ingin mengikuti semuanya adalah ideologi objek, maka itu. Dan bahkan kemudian, contoh ini bahkan tidak menunjukkan semua pabrik yang akan Anda butuhkan dan jika Anda ingin refactor
Compression
danEncryption
kelas dan membuat mereka antarmuka, Anda harus memasukkan implementasinya juga.Pada akhirnya Anda berakhir dengan ratusan kelas kecil dan antarmuka, fokus pada hal-hal yang sangat spesifik. Yang tidak selalu buruk, tetapi mungkin bukan solusi terbaik untuk Anda jika semua yang Anda inginkan adalah melakukan sesuatu yang sederhana seperti menambahkan dua angka.
Jika Anda ingin menyelesaikannya dengan cepat, Anda dapat mengambil solusi Ixrec , yang setidaknya berhasil menghilangkan
else if
danelse
memblokir, yang, menurut pendapat saya, bahkan sedikit lebih buruk daripada dataranif
.Pembaruan 2: Telah ada diskusi liar tentang versi pertama dari solusi saya. Diskusi sebagian besar disebabkan oleh saya, yang saya minta maaf.
Saya memutuskan untuk mengedit jawaban dengan cara yang merupakan salah satu cara untuk melihat solusi tetapi bukan satu-satunya. Saya juga menghapus bagian dekorator, di mana yang saya maksud adalah fasad, yang akhirnya saya putuskan untuk ditinggalkan sepenuhnya, karena adaptor adalah variasi fasad.
sumber
Compression
danEncryption
antarmuka tampak sangat berlebihan. Saya tidak yakin apakah Anda menyarankan bahwa mereka entah bagaimana diperlukan untuk proses dekorasi, atau hanya menyiratkan bahwa mereka mewakili konsep yang diekstraksi. Masalah kedua adalah bahwa membuat kelas sepertiCompressionEncryptionDecorator
mengarah ke jenis ledakan kombinatorial yang sama dengan persyaratan OP. Saya juga tidak melihat pola dekorator cukup jelas dalam kode yang disarankan.Satu-satunya masalah yang saya lihat dengan kode Anda saat ini adalah risiko ledakan kombinatorial saat Anda menambahkan lebih banyak pengaturan, yang dapat dengan mudah dikurangi dengan menyusun kode lebih seperti ini:
Saya tidak mengetahui adanya "pola desain" atau "idiom" yang dapat dianggap sebagai contoh.
sumber
else
antara dua pernyataan if saya, dan mengapa saya menugaskandata
setiap kali. Jika kedua flag benar, maka kompres () dijalankan, kemudian enkripsi () dieksekusi pada hasil kompres (), seperti yang Anda inginkan.Saya kira pertanyaan Anda mencari bukan untuk kepraktisan, dalam hal ini jawaban lxrec adalah yang benar, tetapi untuk belajar tentang pola desain.
Jelas bahwa pola perintah adalah kerja keras untuk masalah sepele seperti yang Anda usulkan tetapi demi ilustrasi, begini:
Seperti yang Anda lihat menempatkan perintah / transformasi dalam daftar memungkinkan untuk dijalankan secara berurutan. Jelas itu akan mengeksekusi keduanya, atau hanya satu dari mereka tergantung pada apa yang Anda masukkan dalam daftar tanpa syarat.
Jelas kondisi akan berakhir di semacam pabrik yang mengumpulkan daftar perintah.
EDIT untuk komentar @ texacre:
Ada banyak cara untuk menghindari kondisi if di bagian kreatif dari solusi, mari kita ambil contoh aplikasi GUI desktop . Anda dapat memiliki kotak centang untuk opsi kompres dan enkripsi. Dalam
on clic
acara mereka kotak centang Anda instantiate perintah yang sesuai dan menambahkannya ke dalam daftar, atau menghapus dari daftar jika Anda tidak memilih opsi tersebut.sumber
commands.add(new EncryptCommand());
ataucommands.add(new CompressCommand());
masing - masing.Saya pikir "pola desain" tidak sesuai diarahkan ke "pola oo" dan sepenuhnya menghindari ide-ide yang jauh lebih sederhana. Yang kita bicarakan di sini adalah pipa data (sederhana).
Saya akan mencoba melakukannya di clojure. Bahasa lain di mana fungsi adalah kelas mungkin juga ok. Mungkin saya bisa contoh C # nanti, tapi tidak sebagus ini. Cara saya memecahkan ini adalah langkah-langkah berikut dengan beberapa penjelasan untuk non-clojurian:
1. Mewakili serangkaian transformasi.
Ini adalah peta, yaitu tabel pencarian / kamus / apa pun, dari kata kunci hingga fungsi. Contoh lain (kata kunci ke string):
Jadi, menulis
(transformations :encrypt)
atau(:encrypt transformations)
akan mengembalikan fungsi terenkripsi. ((fn [data] ... )
hanya fungsi lambda.)2. Dapatkan opsi sebagai urutan kata kunci:
3. Saring semua transformasi menggunakan opsi yang disediakan.
Contoh:
4. Menggabungkan fungsi menjadi satu:
Contoh:
5. Dan kemudian bersama-sama:
HANYA berubah jika kita ingin menambahkan fungsi baru, katakanlah "debug-print", adalah sebagai berikut:
sumber
funcs-to-run-here (map options funcs)
melakukan penyaringan, sehingga memilih serangkaian fungsi untuk diterapkan. Mungkin saya harus memperbarui jawabannya dan masuk ke sedikit lebih detail.[Pada dasarnya, jawaban saya adalah lanjutan dari jawaban oleh @Ixrec di atas . ]
Sebuah pertanyaan penting: apakah jumlah kombinasi berbeda yang perlu Anda bahas akan bertambah? Anda lebih menyadari domain subjek Anda. Ini adalah penilaian Anda untuk dibuat.
Bisakah jumlah varian mungkin bertambah? Yah, itu tidak terbayangkan. Misalnya, Anda mungkin perlu mengakomodasi lebih banyak algoritma enkripsi yang berbeda.
Jika Anda mengantisipasi bahwa jumlah kombinasi berbeda akan bertambah, maka pola Strategi dapat membantu Anda. Itu dirancang untuk merangkum algoritma dan menyediakan antarmuka dipertukarkan ke kode panggilan. Anda masih memiliki sedikit logika ketika Anda membuat (instantiate) strategi yang tepat untuk setiap string tertentu.
Anda telah berkomentar di atas bahwa Anda tidak mengharapkan persyaratan untuk berubah. Jika Anda tidak berharap bahwa jumlah varian akan bertambah (atau jika Anda dapat menunda refactoring ini), maka pertahankan logika tetap seperti semula. Saat ini, Anda memiliki jumlah logika yang kecil dan dapat dikelola. (Mungkin menaruh catatan di komentar tentang kemungkinan refactoring ke pola Strategi.)
sumber
Salah satu cara untuk melakukan ini dalam scala adalah:
Menggunakan pola dekorator untuk mencapai tujuan di atas (pemisahan logika pemrosesan individu dan bagaimana mereka saling terhubung) akan terlalu bertele-tele.
Di mana Anda akan memerlukan pola desain untuk mencapai tujuan desain ini dalam paradigma pemrograman OO, bahasa fungsional menawarkan dukungan asli dengan menggunakan fungsi sebagai warga negara kelas pertama (baris 1 dan 2 dalam kode) dan komposisi fungsional (baris 3)
sumber