Ada dua cara di mana kelas dasar abstrak digunakan.
Anda mengkhususkan objek abstrak Anda, tetapi semua klien akan menggunakan kelas turunan melalui antarmuka dasarnya.
Anda menggunakan kelas dasar abstrak untuk memfaktorkan duplikasi dalam objek dalam desain Anda, dan klien menggunakan implementasi konkret melalui antarmuka mereka sendiri.!
Solusi Untuk 1 - Pola Strategi
Jika Anda memiliki situasi pertama, maka Anda sebenarnya memiliki antarmuka yang ditentukan oleh metode virtual di kelas abstrak yang diterapkan oleh kelas turunan Anda.
Anda harus mempertimbangkan membuat ini antarmuka nyata, mengubah kelas abstrak Anda menjadi konkret, dan mengambil contoh antarmuka ini dalam konstruktornya. Kelas turunan Anda kemudian menjadi implementasi dari antarmuka baru ini.
Ini berarti Anda sekarang dapat menguji kelas abstrak Anda sebelumnya menggunakan contoh tiruan dari antarmuka baru, dan setiap implementasi baru melalui antarmuka sekarang publik. Semuanya sederhana dan dapat diuji.
Solusi untuk 2
Jika Anda memiliki situasi kedua, maka kelas abstrak Anda berfungsi sebagai kelas pembantu.
Lihatlah fungsionalitas yang dikandungnya. Lihat apakah ada yang bisa didorong ke objek yang sedang dimanipulasi untuk meminimalkan duplikasi ini. Jika Anda masih memiliki sesuatu yang tersisa, lihat menjadikannya sebagai kelas pembantu yang implementasi konkret Anda ambil dalam konstruktor mereka dan menghapus kelas dasar mereka.
Ini lagi mengarah ke kelas konkret yang sederhana dan mudah diuji.
Sebagai aturan
Mendukung jaringan kompleks objek sederhana melalui jaringan objek kompleks sederhana.
Kunci kode yang dapat diuji yang dapat diperluas adalah blok bangunan kecil dan kabel independen.
Diperbarui: Bagaimana cara menangani campuran keduanya?
Dimungkinkan untuk memiliki kelas dasar yang melakukan kedua peran ini ... yaitu: ia memiliki antarmuka publik, dan telah melindungi metode pembantu. Jika ini masalahnya, maka Anda dapat memfaktorkan metode helper menjadi satu kelas (skenario2) dan mengubah pohon warisan menjadi pola strategi.
Jika Anda menemukan Anda memiliki beberapa metode yang diterapkan kelas dasar Anda secara langsung dan yang lainnya adalah virtual, maka Anda masih dapat mengubah pohon warisan menjadi pola strategi, tetapi saya juga akan menganggapnya sebagai indikator yang baik bahwa tanggung jawab tidak selaras dengan benar, dan mungkin perlu refactoring.
Pembaruan 2: Kelas Abstrak sebagai batu loncatan (2014/06/12)
Saya mengalami situasi di hari sebelumnya ketika saya menggunakan abstrak, jadi saya ingin mencari tahu mengapa.
Kami memiliki format standar untuk file konfigurasi kami. Alat khusus ini memiliki 3 file konfigurasi semua dalam format itu. Saya ingin kelas yang sangat diketik untuk setiap file pengaturan sehingga, melalui injeksi ketergantungan, kelas bisa meminta pengaturan yang diperhatikannya.
Saya menerapkan ini dengan memiliki kelas dasar abstrak yang tahu bagaimana mem-parsing format file pengaturan dan kelas turunan yang mengekspos metode yang sama, tetapi merangkum lokasi file pengaturan.
Saya bisa menulis "SettingsFileParser" yang dibungkus oleh 3 kelas, dan kemudian didelegasikan ke kelas dasar untuk mengekspos metode akses data. Saya memilih untuk tidak melakukan hal ini belum karena akan mengakibatkan 3 kelas turunan dengan lebih delegasi kode di dalamnya dari apa pun.
Namun ... saat kode ini berkembang dan konsumen dari masing-masing kelas pengaturan ini menjadi lebih jelas. Setiap pengaturan pengguna akan meminta beberapa pengaturan dan mengubahnya dalam beberapa cara (karena pengaturan adalah teks mereka dapat membungkusnya dalam objek untuk mengubahnya menjadi angka dll.). Ketika ini terjadi, saya akan mulai mengekstraksi logika ini ke dalam metode manipulasi data dan mendorongnya kembali ke kelas pengaturan yang diketik dengan kuat. Ini akan mengarah ke antarmuka tingkat yang lebih tinggi untuk setiap set pengaturan, yang pada akhirnya tidak lagi sadar berurusan dengan 'pengaturan'.
Pada titik ini, kelas pengaturan yang sangat diketik tidak lagi memerlukan metode "pengambil" yang mengekspos implementasi 'pengaturan' yang mendasarinya.
Pada saat itu saya tidak ingin lagi antarmuka publik mereka memasukkan metode accessor pengaturan; jadi saya akan mengubah kelas ini untuk merangkum kelas parser pengaturan bukannya berasal dari itu.
Kelas Abstrak karena itu: cara bagi saya untuk menghindari kode delegasi saat ini, dan penanda dalam kode untuk mengingatkan saya untuk mengubah desain nanti. Saya mungkin tidak pernah mencapainya, jadi mungkin tinggal sebentar ... hanya kode yang dapat memberi tahu.
Saya menemukan ini benar dengan aturan apa pun ... seperti "tanpa metode statis" atau "tanpa metode pribadi". Mereka mengindikasikan bau dalam kode ... dan itu bagus. Itu membuat Anda mencari abstraksi yang Anda lewatkan ... dan memungkinkan Anda terus memberikan nilai kepada pelanggan Anda dalam waktu yang bersamaan.
Saya membayangkan aturan seperti ini mendefinisikan lanskap, di mana kode yang dapat dipelihara tinggal di lembah. Saat Anda menambahkan perilaku baru, itu seperti hujan mendarat di kode Anda. Awalnya Anda meletakkannya di mana pun ia mendarat .. lalu Anda refactor untuk memungkinkan kekuatan desain yang baik untuk mendorong perilaku di sekitar sampai semuanya berakhir di lembah.