Jika saya ingin menyimpan dan mengambil objek, haruskah saya membuat kelas lain untuk menanganinya, atau lebih baik melakukannya di kelas itu sendiri? Atau mungkin mencampur keduanya?
Mana yang direkomendasikan sesuai dengan paradigma OOD?
Sebagai contoh
Class Student
{
public string Name {set; get;}
....
public bool Save()
{
SqlConnection con = ...
// Save the class in the db
}
public bool Retrieve()
{
// search the db for the student and fill the attributes
}
public List<Student> RetrieveAllStudents()
{
// this is such a method I have most problem with it
// that an object returns an array of objects of its own class!
}
}
Melawan. (Saya tahu yang berikut ini direkomendasikan, namun menurut saya agak bertentangan dengan kohesi Student
kelas)
Class Student { /* */ }
Class DB {
public bool AddStudent(Student s)
{
}
public Student RetrieveStudent(Criteria)
{
}
public List<Student> RetrieveAllStudents()
{
}
}
Bagaimana kalau mencampurkannya?
Class Student
{
public string Name {set; get;}
....
public bool Save()
{
/// do some business logic!
db.AddStudent(this);
}
public bool Retrieve()
{
// build the criteria
db.RetrieveStudent(criteria);
// fill the attributes
}
}
design
object-oriented
Ahmad
sumber
sumber
Jawaban:
Prinsip Tanggung Jawab Tunggal , Pemisahan Kekhawatiran dan Kohesi Fungsional . Jika Anda membaca konsep-konsep ini, jawaban yang Anda dapatkan adalah: Pisahkan mereka .
Alasan sederhana untuk memisahkan
Student
dari kelas "DB" (atauStudentRepository
, untuk mengikuti konvensi yang lebih populer) adalah untuk memungkinkan Anda mengubah "aturan bisnis" Anda, yang ada diStudent
kelas, tanpa memengaruhi kode yang bertanggung jawab atas ketekunan, dan sebaliknya. sebaliknya.Pemisahan seperti ini sangat penting, tidak hanya antara aturan bisnis dan kegigihan, tetapi di antara banyak masalah sistem Anda, untuk memungkinkan Anda melakukan perubahan dengan dampak minimal pada modul yang tidak terkait (minimal karena kadang-kadang tidak dapat dihindari). Ini membantu untuk membangun sistem yang lebih kuat, yang lebih mudah untuk dipelihara dan lebih dapat diandalkan ketika ada perubahan konstan.
Dengan menggabungkan aturan bisnis dan kegigihan, baik satu kelas seperti pada contoh pertama Anda, atau dengan
DB
ketergantunganStudent
, Anda menggabungkan dua masalah yang sangat berbeda. Itu mungkin terlihat seperti milik mereka bersama; mereka tampaknya kohesif karena mereka menggunakan data yang sama. Tetapi ada satu hal: kohesi tidak dapat diukur hanya dengan data yang dibagikan di antara prosedur, Anda juga harus mempertimbangkan tingkat abstraksi di mana mereka ada. Faktanya, tipe kohesi yang ideal digambarkan sebagai:Dan jelas, melakukan validasi tentang
Student
sementara juga bertahan itu tidak membentuk "tugas tunggal yang jelas". Jadi sekali lagi, aturan bisnis dan mekanisme kegigihan adalah dua aspek yang sangat berbeda dari sistem, yang oleh banyak prinsip desain berorientasi objek yang baik, harus disimpan terpisah.Saya sarankan membaca tentang Arsitektur Bersih , menonton pembicaraan ini tentang Prinsip Tanggung Jawab Tunggal (di mana contoh yang sangat mirip digunakan), dan menonton pembicaraan ini tentang Arsitektur Bersih . Konsep-konsep ini menguraikan alasan di balik pemisahan tersebut.
sumber
Student
kelasnya harus dienkapsulasi dengan benar, ya? Bagaimana kemudian kelas eksternal dapat mengelola kegigihan negara swasta? Enkapsulasi harus seimbang terhadap SoC dan SRP, tetapi hanya memilih salah satu dari yang lain tanpa dengan hati-hati menimbang timbal balik mungkin salah. Solusi yang memungkinkan untuk teka-teki ini adalah menggunakan pengakses paket-pribadi untuk menggunakan kode kegigihan.Kedua pendekatan tersebut melanggar Prinsip Tanggung Jawab Tunggal. Versi pertama Anda memberi
Student
kelas pada banyak tanggung jawab dan mengikatnya dengan teknologi akses DB tertentu. Yang kedua mengarah keDB
kelas besar yang akan bertanggung jawab tidak hanya untuk siswa, tetapi untuk segala jenis objek data dalam program Anda. EDIT: pendekatan ketiga Anda adalah yang terburuk, karena itu menciptakan ketergantungan siklik antara kelas DB danStudent
kelas.Jadi, jika Anda tidak akan menulis program mainan, jangan gunakan satu pun. Alih-alih, gunakan kelas yang berbeda seperti
StudentRepository
untuk menyediakan API untuk memuat dan menyimpan, dengan asumsi Anda akan mengimplementasikan kode CRUD sendiri. Anda mungkin juga mempertimbangkan untuk menggunakan kerangka kerja ORM , yang dapat melakukan kerja keras untuk Anda (dan kerangka kerja tersebut biasanya akan menegakkan beberapa keputusan di mana operasi Muat dan Simpan harus ditempatkan).sumber
Ada beberapa pola yang dapat digunakan untuk kegigihan data. Ada pola Unit Kerja , ada pola Repositori , ada beberapa pola tambahan yang bisa digunakan seperti Remote Facade, dan seterusnya.
Sebagian besar dari mereka memiliki penggemar dan kritik mereka. Seringkali datang untuk memilih apa yang tampaknya paling sesuai dengan aplikasi dan tetap menggunakannya (dengan semua kelebihan dan kekurangannya, yaitu tidak menggunakan kedua pola pada saat yang sama ... kecuali Anda benar-benar yakin tentang itu).
Sebagai catatan tambahan: dalam contoh Anda RetrieveStudent, AddStudent harus berupa metode statis (karena mereka tidak bergantung pada instance).
Cara lain untuk memiliki metode simpan / muat di kelas adalah:
Secara pribadi saya akan menggunakan pendekatan seperti itu hanya dalam aplikasi yang cukup kecil, mungkin alat untuk penggunaan pribadi atau di mana saya dapat memprediksi bahwa saya tidak akan memiliki kasus penggunaan yang lebih rumit daripada hanya menyimpan atau memuat objek.
Juga secara pribadi, lihat pola Unit Kerja. Ketika Anda mengetahuinya, itu sangat bagus dalam kasus kecil dan besar. Dan itu didukung oleh banyak framework / apis, untuk memberi nama EntityFramework atau RavenDB misalnya.
sumber
Jika itu adalah aplikasi yang sangat sederhana di mana objek kurang lebih terikat pada datastore dan sebaliknya (yaitu dapat dianggap sebagai properti dari datastore), maka memiliki metode .save () untuk kelas itu mungkin masuk akal.
Tapi saya pikir itu akan sangat luar biasa.
Sebaliknya, biasanya lebih baik membiarkan kelas mengelola data dan fungsinya (seperti warga negara OO yang baik), dan mengeksternalisasi mekanisme ketekunan ke kelas lain, atau sekumpulan kelas.
Pilihan lain adalah dengan menggunakan kerangka kegigihan yang mendefinisikan kegigihan secara deklaratif (seperti dengan anotasi), tetapi itu masih mengeksternalisasi kegigihan.
sumber
Tentang
RetrieveAllStudents()
metode ini, perasaan Anda benar, mungkin memang salah tempat, karena Anda mungkin memiliki beberapa daftar siswa yang berbeda. Mengapa tidak menyimpan saja daftar di luarStudent
kelas?sumber