Prinsip Tell Don't Don't mengatakan:
Anda harus berusaha memberi tahu objek apa yang Anda ingin mereka lakukan; jangan bertanya kepada mereka tentang keadaan mereka, membuat keputusan, dan kemudian memberi tahu mereka apa yang harus dilakukan.
Masalahnya adalah bahwa, sebagai penelepon, Anda tidak boleh membuat keputusan berdasarkan keadaan objek yang dipanggil yang mengakibatkan Anda kemudian mengubah keadaan objek. Logika yang Anda laksanakan mungkin tanggung jawab objek yang disebut, bukan milik Anda. Bagi Anda untuk membuat keputusan di luar objek melanggar enkapsulasi.
Contoh sederhana "Katakan, jangan Tanya" adalah
Widget w = ...;
if (w.getParent() != null) {
Panel parent = w.getParent();
parent.remove(w);
}
dan versi kirim adalah ...
Widget w = ...;
w.removeFromParent();
Tetapi bagaimana jika saya perlu tahu hasil dari metode removeFromParent? Reaksi pertama saya adalah hanya mengubah removeFromParent untuk mengembalikan boolean yang menunjukkan apakah induk telah dihapus atau tidak.
Tapi kemudian saya menemukan Pola Pemisahan Permintaan Perintah yang mengatakan TIDAK untuk melakukan ini.
Ini menyatakan bahwa setiap metode harus berupa perintah yang melakukan tindakan, atau permintaan yang mengembalikan data ke pemanggil, tetapi tidak keduanya. Dengan kata lain, mengajukan pertanyaan tidak boleh mengubah jawabannya. Lebih formal, metode harus mengembalikan nilai hanya jika mereka secara transparan transparan dan karenanya tidak memiliki efek samping.
Apakah keduanya benar-benar berselisih satu sama lain dan bagaimana saya memilih di antara keduanya? Apakah saya setuju dengan Programmer Pragmatis atau Bertrand Meyer dalam hal ini?
Jawaban:
Sebenarnya masalah contoh Anda sudah menggambarkan kurangnya dekomposisi.
Mari kita ubah sedikit:
Ini tidak terlalu berbeda, tetapi membuat cacatnya lebih jelas: Mengapa buku ini tahu tentang raknya? Sederhananya, seharusnya tidak. Ini memperkenalkan ketergantungan buku di rak (yang tidak masuk akal) dan membuat referensi melingkar. Itu semua buruk.
Demikian juga, tidak perlu bagi widget untuk mengetahui orang tuanya. Anda akan mengatakan: "Ok, tapi widget membutuhkan orangtuanya untuk tata letak yang benar, dll." dan di bawah tenda widget mengetahui orang tuanya dan meminta metrik untuk menghitung metrik sendiri berdasarkan mereka dll. Menurut mengatakan, jangan bertanya ini salah. Orang tua harus memberi tahu semua anaknya untuk memberikan, menyampaikan semua informasi yang diperlukan sebagai argumen. Dengan cara ini seseorang dapat dengan mudah memiliki widget yang sama di dua orang tua (apakah ini benar-benar masuk akal atau tidak).
Untuk kembali ke contoh buku - masukkan pustakawan:
Tolong dimengerti, bahwa kami tidak lagi meminta dalam arti memberi tahu, jangan bertanya .
Dalam versi pertama, rak adalah milik buku dan Anda memintanya. Dalam versi kedua, kami tidak membuat asumsi tentang buku itu. Yang kami tahu adalah bahwa pustakawan dapat memberi tahu kami rak yang berisi buku itu. Agaknya dia bergantung pada semacam tabel pencarian untuk melakukannya, tetapi kita tidak tahu pasti (dia juga bisa memeriksa semua buku di setiap rak) dan sebenarnya kita tidak ingin tahu .
Kami tidak bergantung pada apakah atau bagaimana respons pustakawan digabungkan dengan statusnya atau objek lain yang bergantung padanya. Kami memberi tahu pustakawan untuk menemukan rak.
Dalam skenario pertama, kami secara langsung menyandikan hubungan antara buku dan rak sebagai bagian dari kondisi buku dan mengambil status ini secara langsung. Ini sangat rapuh, karena kami juga membuat asumsi bahwa rak yang diberikan kembali oleh buku berisi buku (ini adalah kendala yang harus kami pastikan, kalau tidak, kami mungkin tidak dapat
remove
mengambil buku dari rak yang sebenarnya ada di dalamnya).Dengan diperkenalkannya pustakawan, kami memodelkan hubungan ini secara terpisah, sehingga mencapai pemisahan perhatian.
sumber
Jika Anda perlu tahu hasilnya, maka Anda lakukan; itu kebutuhan anda .
Ungkapan "metode harus mengembalikan nilai hanya jika mereka secara transparan transparan dan karenanya tidak memiliki efek samping" adalah panduan yang baik untuk diikuti (terutama jika Anda menulis program Anda dengan gaya fungsional , untuk konkurensi atau alasan lain), tetapi itu tidak mutlak.
Misalnya, Anda mungkin perlu mengetahui hasil operasi penulisan file (benar atau salah). Itu adalah contoh metode yang mengembalikan nilai, tetapi selalu menghasilkan efek samping; tidak ada jalan lain untuk itu.
Untuk memenuhi Pemisahan Command / Query, Anda harus melakukan operasi file dengan satu metode, dan kemudian memeriksa hasilnya dengan metode lain, teknik yang tidak diinginkan karena memisahkan hasil dari metode yang menyebabkan hasil. Bagaimana jika sesuatu terjadi pada keadaan objek Anda antara panggilan file dan pemeriksaan status?
Intinya adalah ini: jika Anda menggunakan hasil pemanggilan metode untuk membuat keputusan di tempat lain dalam program ini, maka Anda tidak melanggar Tell Don't Ask. Jika, di sisi lain, Anda membuat keputusan untuk objek berdasarkan panggilan metode ke objek itu, maka Anda harus memindahkan keputusan itu ke objek itu sendiri untuk menjaga enkapsulasi.
Ini sama sekali tidak bertentangan dengan Command Query Separation; pada kenyataannya, itu lebih lanjut menegakkannya, karena tidak ada lagi kebutuhan untuk mengekspos metode eksternal untuk keperluan status.
sumber
Saya pikir Anda harus mengikuti insting awal Anda. Kadang-kadang desain harus sengaja berbahaya, untuk memperkenalkan kompleksitas segera ketika Anda berkomunikasi dengan objek sehingga Anda langsung menanganinya dengan benar, alih-alih mencoba untuk menanganinya pada objek itu sendiri dan menyembunyikan semua detail berdarah dan membuatnya sulit untuk dibersihkan. ubah asumsi yang mendasarinya.
Anda harus mendapatkan perasaan tenggelam jika suatu objek menawarkan Anda menerapkan setara
open
danclose
perilaku dan Anda segera mulai memahami apa yang Anda hadapi ketika Anda melihat nilai pengembalian boolean untuk sesuatu yang Anda pikir akan menjadi tugas atom sederhana.Bagaimana Anda menangani nanti adalah urusan Anda. Anda dapat membuat abstraksi di atasnya, jenis widget
removeFromParent()
, tetapi Anda harus selalu memiliki fallback tingkat rendah, jika tidak, Anda mungkin membuat asumsi prematur.Jangan mencoba menyederhanakan semuanya. Tidak ada yang mengecewakan ketika Anda mengandalkan sesuatu yang tampak elegan dan sangat polos, hanya untuk menyadari bahwa itu adalah horor sejati di saat-saat terburuk.
sumber
Apa yang Anda gambarkan adalah "pengecualian" yang dikenal dengan prinsip Pemisahan Command-Query.
Dalam artikel ini Martin Fowler menjelaskan bagaimana ia akan mengancam pengecualian semacam itu.
Dalam contoh Anda, saya akan mempertimbangkan pengecualian yang sama.
sumber
Pemisahan Command-Query luar biasa mudah disalahpahami.
Jika saya memberi tahu Anda di sistem saya ada perintah yang juga mengembalikan nilai dari permintaan dan Anda berkata "Ha! Anda melanggar!" Anda sedang melompat pistol.
Tidak, bukan itu yang dilarang.
Apa yang dilarang adalah ketika perintah itu adalah cara HANYA untuk membuat permintaan itu. Tidak. Saya tidak perlu mengubah status untuk bertanya. Itu tidak berarti saya harus menutup mata setiap kali saya mengubah keadaan.
Tidak masalah jika saya lakukan karena saya hanya akan membukanya lagi. Satu-satunya keuntungan dari reaksi berlebihan ini adalah memastikan desainer tidak malas dan lupa untuk memasukkan kueri yang tidak berubah.
Arti sebenarnya sangat halus sehingga hanya lebih mudah bagi orang-orang malas untuk mengatakan bahwa penghuni harus kembali batal. Ini membuatnya lebih mudah untuk memastikan bahwa Anda tidak melanggar aturan yang sebenarnya tetapi itu adalah reaksi berlebihan yang bisa menjadi rasa sakit yang nyata.
Antarmuka yang lancar dan iDSL "melanggar" reaksi berlebihan ini sepanjang waktu. Ada banyak kekuatan yang diabaikan jika Anda bereaksi berlebihan.
Anda dapat berdebat bahwa suatu perintah hanya boleh melakukan satu hal dan permintaan seharusnya hanya melakukan satu hal. Dan dalam banyak kasus itu adalah poin yang bagus. Siapa bilang hanya ada satu permintaan yang harus mengikuti perintah? Baik tapi itu bukan pemisahan perintah-permintaan. Itulah prinsip tanggung jawab tunggal.
Tampak seperti ini dan tumpukan pop bukan pengecualian aneh. Ini satu tanggung jawab. Pop hanya melanggar pemisahan kueri perintah jika Anda lupa untuk mengintip.
sumber