Inilah masalah yang sering saya temui: Biarkan ada proyek toko web yang memiliki kelas Produk. Saya ingin menambahkan fitur yang memungkinkan pengguna untuk mengirim ulasan ke suatu produk. Jadi saya memiliki kelas Ulasan yang mereferensikan suatu produk. Sekarang saya membutuhkan metode yang mencantumkan semua ulasan untuk suatu produk. Ada dua kemungkinan:
(SEBUAH)
public class Product {
...
public Collection<Review> getReviews() {...}
}
(B)
public class Review {
...
static public Collection<Review> forProduct( Product product ) {...}
}
Dari melihat kode, saya akan memilih (A): Ini tidak statis dan tidak perlu parameter. Namun, saya merasa bahwa (A) melanggar Prinsip Tanggung Jawab Tunggal (SRP) dan Prinsip Terbuka-Tertutup (OCP) sedangkan (B) tidak:
(SRP) Ketika saya ingin mengubah cara ulasan dikumpulkan untuk suatu produk, saya harus mengubah kelas Produk. Tetapi seharusnya hanya ada satu alasan mengapa mengubah kelas Produk. Dan itu tentu bukan ulasan. Jika saya mengemas setiap fitur yang ada hubungannya dengan produk dalam Produk, itu akan segera berantakan.
(OCP) Saya harus mengubah kelas Produk untuk memperluasnya dengan fitur ini. Saya pikir ini melanggar bagian prinsip 'Tertutup untuk perubahan'. Sebelum saya mendapat permintaan pelanggan untuk menerapkan ulasan, saya menganggap Produk sudah selesai, dan "menutup" itu.
Apa yang lebih penting: mengikuti prinsip SOLID, atau memiliki antarmuka yang lebih sederhana?
Atau apakah saya melakukan sesuatu yang salah di sini?
Hasil
Wow, terima kasih atas semua jawaban Anda yang luar biasa! Sulit untuk memilih satu sebagai jawaban resmi.
Biarkan saya meringkas argumen utama dari jawaban:
- pro (A): OCP juga bukan hukum dan keterbacaan masalah kode.
- pro (A): hubungan entitas harus dinavigasi. Kedua kelas mungkin tahu tentang hubungan ini.
- pro (A) + (B): lakukan keduanya dan delegasikan dalam (A) ke (B) sehingga Produk kecil kemungkinannya untuk diubah lagi.
- pro (C): memasukkan metode finder ke kelas tiga (layanan) yang tidak statis.
- contra (B): menghambat mengejek dalam tes.
Beberapa hal tambahan yang berkontribusi di perguruan tinggi saya:
- pro (B): kerangka kerja ORM kami dapat secara otomatis menghasilkan kode untuk (B).
- pro (A): untuk alasan teknis kerangka ORM kami, akan diperlukan untuk mengubah entitas "tertutup" dalam beberapa kasus, secara independen dari tempat penemu pergi. Jadi saya tidak akan selalu bisa tetap pada SOLID, sih.
- contra (C): terlalu ribut ;-)
Kesimpulan
Saya menggunakan keduanya (A) + (B) dengan delegasi untuk proyek saya saat ini. Namun, dalam lingkungan yang berorientasi layanan, saya akan menggunakan (C).
Assert(5 = Math.Abs(-5));
Abs()
bukanlah masalahnya, menguji sesuatu yang bergantung padanya. Anda tidak memiliki jahitan untuk mengisolasi Code-Under-Test (CUT) yang dependen untuk menggunakan tiruan. Ini berarti Anda tidak dapat mengujinya sebagai unit atom dan semua tes Anda menjadi tes integrasi yang menguji logika unit. Kegagalan dalam suatu tes bisa dalam CUT atau dalam Abs()
(atau kode ketergantungannya) dan menghilangkan manfaat diagnosis dari tes unit.