Ketika mendesain sebuah kelas haruskah konsistensi dalam perilaku lebih disukai daripada praktik pemrograman yang umum? Untuk memberikan contoh spesifik:
Sebuah konvensi umum adalah ini: Jika sebuah kelas memiliki objek (misalnya ia menciptakannya) ia bertanggung jawab untuk membersihkannya setelah selesai. Contoh spesifik akan di .NET bahwa jika kelas Anda memiliki IDisposable
objek itu harus membuangnya di akhir masa pakainya. Dan jika Anda tidak memilikinya maka jangan menyentuhnya.
Sekarang jika kita melihat StreamWriter
kelas di .NET maka kita dapat menemukan dalam dokumentasi bahwa itu menutup aliran yang mendasarinya ketika sedang ditutup / dibuang. Ini diperlukan dalam kasus di mana StreamWriter
instantiated dengan mengirimkan nama file sebagai penulis membuat aliran file yang mendasarinya dan karena itu perlu menutupnya. Namun seseorang juga dapat melewati aliran eksternal yang penulis juga tutup.
Ini telah mengganggu saya banyak kali (ya saya tahu Anda dapat membuat pembungkus non-penutupan tetapi bukan itu intinya) tetapi tampaknya Microsoft telah membuat keputusan bahwa lebih konsisten untuk selalu menutup aliran tidak peduli dari mana asalnya.
Ketika saya menemukan pola seperti itu di salah satu kelas saya, saya biasanya membuat ownsFooBar
bendera yang disetel ke false dalam kasus-kasus di mana FooBar
disuntikkan melalui konstruktor dan untuk benar sebaliknya. Dengan cara ini, tanggung jawab untuk membersihkannya diteruskan ke penelepon ketika dia memberikan contoh secara eksplisit.
Sekarang saya bertanya-tanya apakah mungkin konsistensi lebih disukai daripada praktik terbaik (atau mungkin praktik terbaik saya tidak sebagus itu)? Adakah argumen untuk / menentangnya?
Edit untuk klarifikasi
Dengan "konsistensi" yang saya maksud: Perilaku konsisten kelas selalu mengambil kepemilikan (dan menutup aliran) vs "praktik terbaik" untuk hanya mengambil kepemilikan atas suatu objek jika Anda membuatnya atau secara eksplisit memindahkan kepemilikan.
Adapun contoh di mana itu membuat:
Asumsikan Anda memiliki dua kelas yang diberikan (dari beberapa perpustakaan pihak ke-3) yang menerima aliran untuk melakukan sesuatu dengannya, seperti membuat dan memproses beberapa data:
public class DataProcessor
{
public Result ProcessData(Stream input)
{
using (var reader = new StreamReader(input))
{
...
}
}
}
public class DataSource
{
public void GetData(Stream output)
{
using (var writer = new StreamWriter(output))
{
....
}
}
}
Sekarang saya ingin menggunakannya seperti ini:
Result ProcessSomething(DataSource source)
{
var processor = new DataProcessor();
...
var ms = new MemoryStream();
source.GetData(ms);
return processor.ProcessData(ms);
}
Ini akan gagal kecuali Cannot access a closed stream
di pengolah data. Ini sedikit dibangun tetapi harus menggambarkan intinya. Ada berbagai cara untuk memperbaikinya, namun saya merasa saya harus mengerjakan sesuatu yang seharusnya tidak perlu saya lakukan.
Jawaban:
Saya menggunakan teknik ini juga, saya menyebutnya 'handoff', dan saya percaya itu layak mendapatkan status suatu pola. Ketika suatu objek A menerima objek sekali pakai B sebagai parameter waktu konstruksi, ia juga menerima boolean yang disebut 'handoff', (yang defaultnya salah,) dan jika itu benar, maka pembuangan kaskade A ke pembuangan B.
Saya tidak mendukung untuk memperbanyak pilihan orang lain yang tidak beruntung, jadi saya tidak akan pernah menerima praktik buruk Microsoft sebagai konvensi yang mapan, saya juga tidak akan menganggap orang lain yang membabi buta mengikuti pilihan Microsoft yang tidak menguntungkan sebagai "perilaku konsisten" dengan cara, bentuk atau bentuk apa pun .
sumber
handOff
pola, jika properti seperti itu diatur dalam konstruktor, tetapi ada metode lain untuk memodifikasinya, bahwa metode lain juga harus menerimahandOff
bendera. JikahandOff
ditentukan untuk item yang dipegang saat ini, item itu harus dibuang, maka item baru harus diterima danhandOff
bendera internal diperbarui untuk mencerminkan status item baru. Metode ini tidak perlu memeriksa referensi lama dan baru untuk kesetaraan, karena jika referensi asli "diserahkan" semua referensi yang dimiliki oleh penelepon asli harus ditinggalkan.Dispose
permintaan diabaikan untuk sikat sistem, metode "color.CreateBrush` mungkin akan membuat sikat baru (yang akan membutuhkan pembuangan) atau mengembalikan sikat sistem (yang akan mengabaikan pembuangan). Cara paling sederhana untuk mencegah menggunakan kembali suatu benda jika ia peduli dengan pembuangan, tetapi mengizinkan penggunaan kembali jika tidak, adalah membuangnyaSaya pikir Anda benar, jujur saja. Saya pikir Microsoft mengacaukan kelas StreamWriter, khususnya, untuk alasan yang Anda jelaskan.
Namun, sejak itu saya telah melihat banyak kode di mana orang bahkan tidak mencoba membuang Stream mereka sendiri karena kerangka kerja akan melakukannya untuk mereka, jadi memperbaikinya sekarang akan lebih berbahaya daripada manfaatnya.
sumber
Saya akan pergi dengan konsistensi. Seperti yang Anda sebutkan kepada kebanyakan orang, masuk akal bahwa jika objek Anda membuat objek anak, ia akan memiliki dan menghancurkannya. Jika diberi referensi dari luar, pada suatu saat "luar" juga memegang benda yang sama dan tidak boleh dimiliki. Jika Anda ingin mentransfer kepemilikan dari luar ke objek Anda menggunakan metode Lampirkan / Lepaskan atau konstruktor yang menerima boolean yang menjelaskan kepemilikan yang ditransfer.
Setelah mengetik semua itu untuk jawaban yang lengkap, saya pikir sebagian besar pola desain umum tidak akan jatuh ke dalam kategori yang sama dengan kelas StreamWriter / StreamReader. Saya selalu berpikir bahwa alasan MS memilih agar StreamWriter / Reader secara otomatis mengambil alih kepemilikan adalah karena dalam contoh khusus ini, memiliki kepemilikan bersama tidak masuk akal. Anda tidak dapat memiliki dua objek berbeda secara bersamaan membaca dari / menulis ke aliran yang sama. Saya yakin Anda bisa menulis semacam pembagian waktu yang deterministik, tetapi itu akan menjadi semacam anti-pola. Jadi itu mungkin mengapa mereka berkata, karena tidak masuk akal untuk berbagi aliran, mari kita selalu mengambil alih. Tetapi saya tidak akan menganggap perilaku ini pernah menjadi konvensi generik di seluruh kelas untuk semua kelas.
Anda dapat menganggap Streams sebagai pola yang konsisten di mana objek yang dilewatkan tidak dapat dibedakan dari sudut pandang desain dan karenanya tanpa bendera tambahan, pembaca / penulis hanya mengambil alih kepemilikannya.
sumber
Hati-hati. Apa yang Anda anggap sebagai "konsistensi" mungkin hanya kumpulan kebiasaan acak.
"Mengkoordinasikan antarmuka pengguna untuk konsistensi", SIGCHI Bulletin 20, (1989), 63-65. Maaf, tidak ada tautan, ini adalah artikel lama. "... lokakarya dua hari yang terdiri dari 15 ahli tidak dapat menghasilkan definisi konsistensi." Ya, ini tentang "antarmuka", tetapi saya percaya bahwa jika Anda berpikir tentang "konsistensi" untuk sementara waktu, Anda akan menemukan Anda juga tidak dapat mendefinisikannya.
sumber