Saya memiliki metode yang memperbarui data karyawan dalam database. The Employee
kelas berubah, sehingga "memperbarui" sarana objek sebenarnya untuk instantiate objek baru.
Saya ingin Update
metode untuk kembali contoh baru dari Employee
dengan data diperbarui, tapi karena sekarang saya dapat mengatakan tanggung jawab dari metode ini adalah untuk memperbarui data karyawan, dan mengambil dari database baru Employee
objek , apakah itu melanggar Tanggung Jawab Single Prinsip ?
Catatan DB itu sendiri diperbarui. Kemudian, objek baru dipakai untuk mewakili catatan ini.
Compare-and-swap
dantest-and-set
merupakan operasi mendasar dalam teori pemrograman multi-utas. Keduanya merupakan metode pembaruan dengan tipe pengembalian, dan tidak bisa berfungsi sebaliknya. Apakah ini melanggar konsep seperti pemisahan perintah-permintaan atau Prinsip Tanggung Jawab Tunggal? Ya, dan itulah intinya . SRP bukan hal yang baik secara universal, dan sebenarnya bisa berbahaya secara aktif.Jawaban:
Seperti halnya aturan apa pun, saya pikir yang penting di sini adalah mempertimbangkan tujuan aturan, semangat, dan tidak terperosok dalam menganalisis dengan tepat bagaimana aturan itu ditulis dalam beberapa buku teks dan bagaimana menerapkannya pada kasus ini. Kami tidak perlu mendekati ini seperti pengacara. Tujuan peraturan ini adalah untuk membantu kami menulis program yang lebih baik. Bukannya tujuan program menulis adalah untuk menegakkan aturan.
Tujuan dari aturan tanggung jawab tunggal adalah untuk membuat program lebih mudah dipahami dan dipelihara dengan membuat setiap fungsi melakukan satu hal yang koheren dan mandiri.
Sebagai contoh, saya pernah menulis sebuah fungsi yang saya sebut sesuatu seperti "checkOrderStatus", yang menentukan apakah pesanan tertunda, dikirimkan, dipesan kembali, apa pun, dan mengembalikan kode yang menunjukkan. Kemudian programmer lain datang dan memodifikasi fungsi ini untuk juga memperbarui kuantitas saat pesanan dikirim. Ini sangat melanggar prinsip tanggung jawab tunggal. Programmer lain yang membaca kode itu nanti akan melihat nama fungsinya, melihat bagaimana nilai pengembalian digunakan, dan mungkin tidak pernah menduga bahwa ia melakukan pembaruan basis data. Seseorang yang perlu mendapatkan status pesanan tanpa memperbarui kuantitas yang ada akan berada dalam posisi yang canggung: haruskah ia menulis fungsi baru yang menggandakan bagian status pesanan? Tambahkan bendera untuk memberi tahu apakah akan melakukan pembaruan db? Dll
Di sisi lain, saya tidak akan menganggap apa yang merupakan "dua hal". Saya baru-baru ini menulis sebuah fungsi yang mengirimkan informasi pelanggan dari sistem kami ke sistem klien kami. Fungsi itu melakukan beberapa pemformatan ulang data untuk memenuhi persyaratan mereka. Misalnya, kami memiliki beberapa bidang yang mungkin nol pada basis data kami, tetapi tidak mengizinkan nol sehingga kami harus mengisi beberapa teks dummy, "tidak ditentukan" atau saya lupa kata-kata yang tepat. Bisa dibilang fungsi ini melakukan dua hal: memformat ulang data DAN mengirimkannya. Tapi saya sengaja menempatkan ini dalam satu fungsi daripada memiliki "memformat ulang" dan "mengirim" karena saya tidak ingin pernah, pernah mengirim tanpa memformat ulang. Saya tidak ingin seseorang menulis panggilan baru dan tidak menyadari bahwa ia harus memanggil reformat dan kemudian mengirim.
Dalam kasus Anda, perbarui basis data dan kembalikan gambar catatan yang dituliskan tampak seperti dua hal yang mungkin berjalan secara logis dan tak terelakkan. Saya tidak tahu detail aplikasi Anda, jadi saya tidak bisa mengatakan dengan pasti apakah ini ide yang bagus atau tidak, tetapi kedengarannya masuk akal.
Jika Anda membuat objek dalam memori yang menyimpan semua data untuk catatan, melakukan panggilan database untuk menulis ini, dan kemudian mengembalikan objek, ini sangat masuk akal. Anda memiliki benda di tangan Anda. Mengapa tidak mengembalikannya saja? Jika Anda tidak mengembalikan objek, bagaimana penelepon mendapatkannya? Apakah dia harus membaca database untuk mendapatkan objek yang baru saja Anda tulis? Tampaknya agak tidak efisien. Bagaimana dia menemukan catatan itu? Apakah Anda tahu kunci utama? Jika seseorang menyatakan bahwa itu "sah" untuk fungsi tulis untuk mengembalikan kunci utama sehingga Anda dapat membaca kembali catatan, mengapa tidak hanya mengembalikan seluruh catatan sehingga Anda tidak perlu melakukannya? Apa bedanya?
Di sisi lain, jika membuat objek adalah kumpulan pekerjaan yang sangat berbeda dari menulis catatan database, dan penelepon mungkin ingin melakukan penulisan tetapi tidak membuat objek, maka ini bisa menjadi pemborosan. Jika seorang penelepon mungkin menginginkan objek tetapi tidak melakukan penulisan, maka Anda harus memberikan cara lain untuk mendapatkan objek, yang bisa berarti menulis kode yang berlebihan.
Tapi saya pikir skenario 1 lebih mungkin, jadi saya katakan, mungkin tidak ada masalah.
sumber
public function sendDataInClientFormat() { formatDataForClient(); sendDataToClient(); } private function formatDataForClient() {...} private function sendDataToClient() {...}
Konsep SRP adalah untuk menghentikan modul melakukan 2 hal berbeda ketika melakukannya secara individual membuat untuk pemeliharaan yang lebih baik dan lebih sedikit spageti dalam waktu. Seperti kata SRP "satu alasan untuk berubah".
Dalam kasus Anda, jika Anda memiliki rutin yang "memperbarui dan mengembalikan objek yang diperbarui", Anda masih mengubah objek satu kali - memberikannya 1 alasan untuk berubah. Bahwa Anda mengembalikan objek kembali tidak ada di sini atau di sana, Anda masih beroperasi pada objek tunggal itu. Kode memiliki tanggung jawab untuk satu, dan hanya satu, hal.
SRP tidak benar-benar mencoba mengurangi semua operasi menjadi satu panggilan, tetapi untuk mengurangi apa yang Anda operasikan dan bagaimana Anda mengoperasikannya. Jadi satu pembaruan yang mengembalikan objek yang diperbarui baik-baik saja.
sumber
Seperti biasa, ini masalah derajat. SRP harus menghentikan Anda dari menulis metode yang mengambil catatan dari database eksternal, melakukan transformasi Fourier cepat di atasnya dan memperbarui registri statistik global dengan hasilnya. Saya pikir hampir semua orang akan setuju bahwa hal-hal ini harus dilakukan dengan metode berbeda. Mendalilkan satu tanggung jawab tunggal untuk setiap metode hanyalah cara yang paling ekonomis dan mudah diingat untuk menyatakan hal itu.
Di ujung lain dari spektrum adalah metode yang menghasilkan informasi tentang keadaan suatu objek. Khas
isActive
telah memberikan informasi ini sebagai tanggung jawab tunggal. Mungkin semua orang setuju bahwa ini baik-baik saja.Sekarang, beberapa memperluas prinsip sejauh mereka menganggap mengembalikan bendera sukses tanggung jawab yang berbeda dari melakukan tindakan yang keberhasilannya dilaporkan. Di bawah interpretasi yang sangat ketat, ini benar, tetapi karena alternatifnya harus memanggil metode kedua untuk mendapatkan status keberhasilan, yang menyulitkan penelepon, banyak programmer yang baik-baik saja dengan mengembalikan kode sukses dari metode dengan efek samping.
Mengembalikan objek baru adalah selangkah lebih maju dalam perjalanan menuju beberapa tanggung jawab. Membutuhkan pemanggil untuk membuat panggilan kedua untuk seluruh objek sedikit lebih masuk akal daripada membutuhkan panggilan kedua hanya untuk melihat apakah yang pertama berhasil atau tidak. Namun, banyak programmer akan mempertimbangkan untuk mengembalikan hasil pembaruan dengan sangat baik. Meskipun hal ini dapat ditafsirkan sebagai dua tanggung jawab yang sedikit berbeda, sudah barang tentu bukan salah satu pelanggaran mengerikan yang mengilhami prinsip tersebut.
sumber
Apakah itu melanggar Prinsip Tanggung Jawab Tunggal?
Belum tentu. Jika ada, ini melanggar prinsip pemisahan perintah-kueri .
Tanggung jawabnya adalah
dengan pemahaman implisit bahwa tanggung jawab ini mencakup status operasi; misalnya, jika operasi gagal, pengecualian dilemparkan, jika berhasil, karyawan pembaruan dikembalikan, dll.
Sekali lagi, ini semua masalah tingkat dan penilaian subyektif.
Jadi bagaimana dengan pemisahan perintah-permintaan?
Ya, prinsip itu ada, tetapi mengembalikan hasil pembaruan sebenarnya sangat umum.
(1) Java
Set#add(E)
menambahkan elemen dan mengembalikan inklusi sebelumnya di set.Ini lebih efisien daripada alternatif CQS, yang mungkin harus melakukan dua pencarian.
(2) Compare-and-swap , fetch-and-add , dan test-and-set adalah primitif umum yang memungkinkan pemrograman bersamaan ada. Pola-pola ini sering muncul, dari instruksi CPU tingkat rendah hingga koleksi bersamaan tingkat tinggi.
sumber
Tanggung jawab tunggal adalah tentang kelas yang tidak perlu diubah karena lebih dari satu alasan.
Sebagai contoh, seorang karyawan memiliki daftar nomor telepon. Ketika cara Anda menangani nomor telepon berubah (Anda dapat menambahkan kode panggilan negara) yang seharusnya tidak mengubah kelas karyawan sama sekali.
Saya tidak akan memiliki kelas karyawan yang perlu tahu bagaimana cara menyimpan sendiri ke database, karena itu akan berubah untuk perubahan karyawan dan perubahan dalam bagaimana data disimpan.
Serupa seharusnya tidak ada metode CalculateSalary di kelas karyawan. Properti gaji tidak apa-apa, tetapi perhitungan pajak dll. Harus dilakukan di tempat lain.
Tetapi metode Pembaruan mengembalikan apa yang baru saja diperbarui baik-baik saja.
sumber
Wrt. kasus spesifik:
Ini tampaknya yang
Update
Cara mengambil yang adaEmployee
sebagai parameter pertama yang mengidentifikasi (?) Karyawan yang ada dan satu set parameter perubahan pada karyawan ini.Saya tidak pikir ini bisa menjadi dilakukan bersih. Saya melihat dua kasus:
(a)
Employee
benar-benar berisi database / ID unik yang dengannya selalu dapat diidentifikasi dalam database. (Yaitu, Anda tidak perlu seluruh nilai rekaman ditetapkan untuk menemukannya di DB.Dalam hal ini, saya lebih suka
void Update(Employee obj)
metode, yang hanya menemukan catatan yang ada dengan ID dan kemudian memperbarui bidang dari objek yang diteruskan. Atau mungkin sebuahvoid Update(ID, EmployeeBuilder values)
Variasi dari hal ini yang menurut saya berguna adalah hanya memiliki
void Put(Employee obj)
metode yang memasukkan atau memperbarui, tergantung pada apakah ada catatan (berdasarkan ID).(b) Rekor yang ada penuh diperlukan untuk DB lookup, dalam kasus ini mungkin masih lebih masuk akal untuk memiliki:
void Update(Employee existing, Employee newData)
.Sejauh yang saya bisa lihat di sini, saya memang akan mengatakan bahwa tanggung jawab membangun objek baru (atau nilai-nilai sub-objek) untuk menyimpan dan benar-benar menyimpannya adalah ortogonal, jadi saya akan memisahkannya.
Persyaratan konkuren yang disebutkan dalam jawaban lain (set atom dan ambil / bandingkan-swap, dll) belum menjadi masalah dalam kode DB yang saya kerjakan sejauh ini. Ketika berbicara dengan DB, saya pikir ini harus ditangani pada tingkat transaksi secara normal, bukan pada tingkat pernyataan individu. (Bukan untuk mengatakan bahwa mungkin tidak ada desain di mana "atom"
Employee[existing data] Update(ID, Employee newData)
tidak masuk akal, tetapi dengan DB mengaksesnya bukan sesuatu yang biasanya saya lihat.)sumber
Sejauh ini semua orang di sini berbicara tentang kelas. Tapi pikirkanlah dari sudut pandang antarmuka.
Jika metode antarmuka menyatakan tipe pengembalian, dan / atau janji tersirat tentang nilai kembali, maka setiap implementasi perlu mengembalikan objek yang diperbarui.
Jadi, Anda dapat bertanya:
Juga pikirkan benda tiruan untuk pengujian unit. Jelas akan lebih mudah untuk mengejek tanpa nilai balik. Dan komponen dependen lebih mudah untuk diuji, jika dependensinya yang disuntikkan memiliki antarmuka yang lebih sederhana.
Berdasarkan pertimbangan ini Anda dapat membuat keputusan.
Dan jika Anda menyesal nanti, Anda masih bisa memperkenalkan antarmuka kedua, dengan adaptor di antara keduanya. Tentu saja antarmuka tambahan seperti itu meningkatkan kompleksitas komposisi, sehingga semuanya merupakan pertukaran.
sumber
Pendekatan Anda baik-baik saja. Kekekalan adalah pernyataan yang kuat. Satu-satunya hal yang akan saya tanyakan adalah: Apakah ada tempat lain di mana Anda membangun objek. Jika objek Anda tidak berubah, Anda harus menjawab pertanyaan tambahan karena "Status" diperkenalkan. Dan perubahan keadaan suatu objek dapat terjadi dengan alasan yang berbeda. Maka Anda harus tahu kasus Anda dan tidak boleh berlebihan atau terbagi.
sumber