Mencari beberapa saran desain OO

12

Saya sedang mengembangkan aplikasi yang akan digunakan untuk membuka dan menutup katup di lingkungan industri, dan memikirkan sesuatu yang sederhana seperti ini: -

public static void ValveController
{
    public static void OpenValve(string valveName)
    {
        // Implementation to open the valve
    }

    public static void CloseValve(string valveName)
    {
        // Implementation to close the valve
    }
}

(Implementasi akan menulis beberapa byte data ke port serial untuk mengontrol katup - "alamat" yang berasal dari nama katup, dan "1" atau "0" untuk membuka atau menutup katup).

Pengembang lain bertanya apakah kita harus membuat kelas terpisah untuk setiap katup fisik, yang jumlahnya puluhan. Saya setuju akan lebih baik untuk menulis kode seperti PlasmaValve.Open()daripada ValveController.OpenValve("plasma"), tetapi apakah ini berlebihan?

Juga, saya bertanya-tanya bagaimana cara terbaik untuk menangani desain dengan beberapa persyaratan masa depan hipotetis dalam pikiran: -

  1. Kami diminta untuk mendukung jenis katup baru yang membutuhkan nilai berbeda untuk membuka dan menutupnya (bukan 0 dan 1).
  2. Kami diminta untuk mendukung katup yang dapat disetel ke posisi apa pun dari 0-100, daripada hanya "terbuka" atau "tertutup".

Biasanya saya akan menggunakan warisan untuk hal semacam ini, tetapi saya baru-baru ini mulai mendapatkan sekitar "komposisi atas warisan" dan bertanya-tanya apakah ada solusi yang lebih licin yang bisa didapat dengan menggunakan komposisi?

Andrew Stephens
sumber
2
Saya akan membuat kelas katup generik yang memiliki pengidentifikasi untuk katup spesifik (bukan string, mungkin enum) dan informasi apa pun yang diperlukan untuk aliran kontrol di dalam metode OpenValve / CloseValve. Atau Anda bisa membuat abstrak kelas valv dan membuat implementasi terpisah untuk masing-masing, di mana katup buka / tutup hanya memanggil logika di dalam kelas katup yang diberikan untuk kejadian bahwa katup yang berbeda memiliki mekanisme pembukaan / penutupan yang berbeda. Mekanisme umum akan didefinisikan dalam kelas dasar.
Jimmy Hoffa
2
Jangan khawatir tentang persyaratan masa depan hipotetis. YAGNI.
pdr
3
@ pdr YAGNI adalah bilah bermata dua, saya setuju ada baiknya mengikuti secara umum, tetapi dibawa ke ekstrem yang bisa mengatakan melakukan apa saja untuk membantu pemeliharaan atau keterbacaan di masa depan melanggar YAGNI, karena ini saya menemukan lingkup YAGNI terlalu ambigu untuk banyak. Yang mengatakan, banyak orang mengenali di mana harus menggunakan YAGNI dan di mana harus membuangnya karena memperhitungkan masa depan akan menyelamatkan Anda dari rasa sakit yang serius. Saya hanya berpikir seseorang harus berhati-hati menyarankan orang mengikuti YAGNI ketika Anda tidak tahu di mana mereka akan mendarat pada spektrum itu.
Jimmy Hoffa
2
Man, 'komposisi atas warisan' dilebih-lebihkan. Saya akan membuat kelas / antarmuka abstrak Valve dan kemudian mengelompokkannya ke dalam PlasmaValve. Dan kemudian saya akan memastikan bahwa ValveController saya akan bekerja dengan Valve (s), tidak peduli tentang subclass mana mereka sebenarnya.
MrFox
2
@suslik: Tentu saja. Saya juga melihat kode luar biasa yang disebut spaghetti oleh orang-orang yang tidak mengerti prinsip SOLID. Kita bisa terus selamanya dengan ini. Maksud saya adalah bahwa saya telah melihat lebih banyak masalah yang disebabkan oleh pengabaian prinsip-prinsip yang sudah mapan (lahir dari pengalaman bertahun-tahun) di luar tangan daripada yang saya lihat disebabkan oleh kepatuhan yang berlebihan. Tetapi saya setuju bahwa kedua ekstrem itu berbahaya.
pdr

Jawaban:

12

Jika setiap instance dari objek valve akan menjalankan kode yang sama dengan ValveController ini, maka sepertinya beberapa instance dari satu kelas akan menjadi cara yang tepat. Dalam hal ini, cukup konfigurasikan katup mana yang dikontrolnya (dan bagaimana) di konstruktor objek katup.

Namun jika setiap kontrol katup memerlukan kode yang berbeda untuk dijalankan, dan ValveController saat ini menjalankan pernyataan saklar raksasa yang melakukan hal-hal yang berbeda tergantung pada jenis katup, maka Anda telah menerapkan kembali polimorfisme dengan buruk. Dalam hal itu, tulis ulang ke beberapa kelas dengan basis umum (jika itu masuk akal) dan biarkan prinsip tanggung jawab tunggal menjadi panduan desain Anda.

stonemetal
sumber
1
+1 untuk menyebutkan pernyataan switch berbasis tipe sebagai kode bau. Saya sering melihat pernyataan switch seperti ini di mana pengembang mengklaim dia hanya mengikuti KISS. Contoh sempurna tentang bagaimana prinsip-prinsip desain dapat diubah, heh
Jimmy Hoffa
2
Beberapa contoh juga dapat memudahkan untuk menghubungkan katup secara berurutan, memungkinkan Anda untuk memodelkan perpipaan instalasi aktual sebagai grafik berarah dalam kode Anda. Anda juga dapat menambahkan logika bisnis ke kelas, jika Anda perlu melakukan sesuatu seperti membuka satu katup ketika yang lain ditutup untuk menghindari penumpukan tekanan, atau menutup semua katup hilir sehingga Anda tidak mendapatkan efek "water hammer" ketika katup dibuka lagi.
TMN
1

Keluhan utama saya adalah menggunakan string untuk parameter yang mengidentifikasi katup.

Setidaknya buat Valvekelas yang memiliki getAddressdalam bentuk kebutuhan implementasi yang mendasarinya dan berikan kepada ValveControllerdan pastikan bahwa Anda tidak dapat membuat katup yang tidak ada. Dengan cara ini Anda tidak perlu menangani string yang salah di setiap metode buka dan tutup.

Apakah Anda membuat metode kenyamanan yang memanggil buka dan tutup ValveControlleradalah terserah Anda, tetapi jujur ​​saya akan menyimpan semua komunikasi ke port serial (termasuk pengkodean) dalam satu kelas yang akan dipanggil oleh kelas lain bila diperlukan. Ini berarti bahwa ketika Anda perlu bermigrasi ke controller baru Anda hanya perlu memodifikasi satu kelas.

Jika Anda menyukai pengujian, Anda juga harus membuat ValveControllersingleton sehingga Anda dapat mengejeknya (atau membuat mesin pelatihan untuk operator).

aneh ratchet
sumber
Saya belum pernah melihat orang merekomendasikan singleton demi pengujian sebelumnya - biasanya itu sebaliknya.
Kazark
Jujur singleton lebih untuk menghindari statika sehingga komunikasi dapat disinkronkan
ratchet freak