Mari kita mundur dan melihat gambaran yang lebih besar di sini.
Apa IDatabase
tanggung jawabnya?
Ini memiliki beberapa operasi berbeda:
- Parsing string koneksi
- Buka koneksi dengan database (sistem eksternal)
- Kirim pesan ke basis data; pesan memerintahkan database untuk mengubah statusnya
- Menerima tanggapan dari database dan mengubahnya menjadi format yang dapat digunakan penelepon
- Tutup koneksi
Melihat daftar ini, Anda mungkin berpikir, "Bukankah ini melanggar SRP?" Tapi saya rasa tidak. Semua operasi adalah bagian dari konsep kohesif tunggal: mengelola koneksi stateful ke database (sistem eksternal) . Itu membuat koneksi, itu melacak keadaan koneksi saat ini (dalam kaitannya dengan operasi yang dilakukan pada koneksi lain, khususnya), itu menandakan kapan melakukan keadaan koneksi saat ini, dll. Dalam hal ini, ia bertindak sebagai API yang menyembunyikan banyak detail implementasi yang tidak dipedulikan oleh sebagian besar penelepon. Misalnya, apakah menggunakan HTTP, soket, pipa, TCP kustom, HTTPS? Kode panggilan tidak peduli; ia hanya ingin mengirim pesan dan mendapat tanggapan. Ini adalah contoh enkapsulasi yang bagus.
Apakah kita yakin Tidak bisakah kita memisahkan beberapa operasi ini? Mungkin, tetapi tidak ada manfaatnya. Jika Anda mencoba untuk membaginya, Anda masih akan membutuhkan objek pusat yang membuat koneksi tetap terbuka dan / atau mengelola keadaan saat ini. Semua operasi lainnya sangat digabungkan ke negara yang sama, dan jika Anda mencoba untuk memisahkan mereka, mereka hanya akan berakhir mendelegasikan kembali ke objek koneksi. Operasi-operasi ini secara alami dan logis digabungkan ke negara, dan tidak ada cara untuk memisahkannya. Decoupling sangat bagus ketika kita bisa melakukannya, tetapi dalam kasus ini, kita sebenarnya tidak bisa. Setidaknya bukan tanpa protokol stateless yang sangat berbeda untuk berbicara dengan DB, dan itu akan membuat masalah yang sangat penting seperti kepatuhan ACID menjadi lebih sulit. Juga, dalam proses mencoba memisahkan operasi-operasi ini dari koneksi, Anda akan dipaksa untuk mengekspos detail tentang protokol yang tidak dipedulikan penelepon, karena Anda akan memerlukan cara mengirim semacam pesan "sewenang-wenang" ke database.
Perhatikan bahwa fakta yang kita hadapi dengan protokol stateful cukup mengesampingkan alternatif terakhir Anda (melewati string koneksi sebagai parameter).
Apakah kita benar-benar membutuhkan string koneksi untuk diatur?
Iya. Anda tidak dapat membuka koneksi sampai Anda memiliki string koneksi, dan Anda tidak dapat melakukan apa pun dengan protokol sampai Anda membuka koneksi. Jadi tidak ada gunanya memiliki objek koneksi tanpa satu.
Bagaimana kita memecahkan masalah yang membutuhkan string koneksi?
Masalah yang kita coba selesaikan adalah bahwa kita ingin objek berada dalam kondisi yang dapat digunakan setiap saat. Entitas apa yang digunakan untuk mengelola status dalam bahasa OO? Objek , bukan antarmuka. Antarmuka tidak memiliki negara untuk dikelola. Karena masalah yang Anda coba selesaikan adalah masalah manajemen negara, antarmuka tidak benar-benar sesuai di sini. Kelas abstrak jauh lebih alami. Jadi gunakan kelas abstrak dengan konstruktor.
Anda mungkin juga ingin mempertimbangkan untuk benar-benar membuka koneksi selama konstruktor, karena koneksi juga tidak berguna sebelum dibuka. Itu akan membutuhkan protected Open
metode abstrak karena proses membuka koneksi mungkin spesifik database. Ini juga merupakan ide yang baik untuk membuat ConnectionString
properti hanya membaca dalam kasus ini, karena mengubah string koneksi setelah koneksi terbuka tidak akan berarti. (Jujur, saya hanya akan membuatnya membaca. Jika Anda ingin koneksi dengan string yang berbeda, buat objek lain.)
Apakah kita memerlukan antarmuka sama sekali?
Antarmuka yang menentukan pesan yang tersedia yang dapat Anda kirim melalui koneksi dan jenis respons yang bisa Anda dapatkan kembali bisa berguna. Ini akan memungkinkan kita untuk menulis kode yang mengeksekusi operasi ini tetapi tidak digabungkan dengan logika membuka koneksi. Tapi itu intinya: mengelola koneksi bukan bagian dari antarmuka, "Pesan apa yang bisa saya kirim dan pesan apa yang bisa saya dapatkan kembali ke / dari database?", Jadi string koneksi seharusnya tidak menjadi bagian dari itu antarmuka.
Jika kita melewati rute ini, kode kita mungkin terlihat seperti ini:
interface IDatabase {
void ExecuteNoQuery(string sql);
void ExecuteNoQuery(string[] sql);
//Various other methods all requiring ConnectionString to be set
}
abstract class ConnectionStringDatabase : IDatabase {
public string ConnectionString { get; }
public Database(string connectionString) {
this.ConnectionString = connectionString;
this.Open();
}
protected abstract void Open();
public abstract void ExecuteNoQuery(string sql);
public abstract void ExecuteNoQuery(string[] sql);
//Various other methods all requiring ConnectionString to be set
}