Pertanyaan tentang kapan menggunakan privat dan kapan menggunakan protected di kelas membuat saya berpikir. (Saya akan memperluas pertanyaan ini juga ke kelas dan metode akhir, karena terkait. Saya pemrograman di Jawa, tapi saya pikir ini relevan untuk setiap bahasa OOP)
Aturan praktis yang baik adalah: jadikan segala sesuatu senyaman mungkin.
- Jadikan semua kelas final kecuali jika Anda perlu subklas segera.
- Buat semua metode menjadi final kecuali Anda perlu membuat subkelas dan menimpanya segera.
- Buat semua parameter metode final kecuali Anda perlu mengubahnya di dalam tubuh metode, yang agak canggung sebagian besar kali.
Ini cukup mudah dan jelas, tetapi bagaimana jika saya kebanyakan menulis perpustakaan (Open Source on GitHub) alih-alih aplikasi?
Saya bisa menyebutkan banyak perpustakaan dan situasi, di mana
- Perpustakaan diperluas dengan cara yang tidak pernah dipikirkan pengembang
- Ini harus dilakukan dengan "magic loader kelas" dan peretasan lainnya karena kendala visibilitas
- Perpustakaan digunakan dengan cara yang tidak dibuat untuknya dan fungsi fungsionalitas yang diperlukan "diretas"
- Perpustakaan tidak dapat digunakan karena masalah kecil (bug, fungsionalitas yang hilang, perilaku "salah") yang tidak dapat diubah karena visibilitas berkurang
- Masalah yang tidak dapat diperbaiki mengarah pada solusi besar, jelek dan bermasalah di mana mengesampingkan fungsi sederhana (yang bersifat pribadi atau final) dapat membantu
Dan saya benar-benar mulai memberi nama ini sampai pertanyaannya menjadi terlalu panjang dan saya memutuskan untuk menghapusnya.
Saya suka gagasan tidak memiliki lebih banyak kode daripada yang dibutuhkan, lebih banyak visibilitas daripada yang dibutuhkan, lebih banyak abstraksi daripada yang dibutuhkan. Dan ini mungkin berfungsi saat menulis aplikasi untuk pengguna akhir, di mana kode hanya digunakan oleh mereka yang menulisnya. Tetapi bagaimana ini bisa bertahan jika kode dimaksudkan untuk digunakan oleh pengembang lain, di mana tidak mungkin bahwa pengembang asli memikirkan setiap kasus penggunaan yang mungkin di muka dan perubahan / refaktor sulit / tidak mungkin dibuat?
Karena pustaka sumber terbuka besar bukanlah hal yang baru, apa cara paling umum untuk menangani visibilitas dalam proyek semacam itu dengan bahasa berorientasi objek?
Jawaban:
Kebenaran yang disayangkan adalah bahwa banyak perpustakaan ditulis , bukan dirancang . Ini menyedihkan, karena sedikit pemikiran sebelumnya dapat mencegah banyak masalah di jalan.
Jika kita mulai mendesain perpustakaan, akan ada beberapa kasus penggunaan yang diantisipasi. Perpustakaan mungkin tidak memuaskan semua kasus penggunaan secara langsung, tetapi dapat berfungsi sebagai bagian dari solusi. Jadi perpustakaan perlu cukup fleksibel untuk beradaptasi.
Kendala adalah bahwa biasanya bukan ide yang baik untuk mengambil kode sumber perpustakaan dan memodifikasinya untuk menangani kasus penggunaan baru. Untuk pustaka berpemilik, sumbernya mungkin tidak tersedia, dan untuk pustaka sumber terbuka mungkin tidak diinginkan untuk mempertahankan versi bercabang. Mungkin tidak layak untuk menggabungkan adaptasi yang sangat spesifik ke dalam proyek hulu.
Di sinilah prinsip buka-tutup muncul: perpustakaan harus terbuka untuk ekstensi tanpa mengubah kode sumber. Itu tidak datang secara alami. Ini harus menjadi tujuan desain yang disengaja. Ada banyak teknik yang dapat membantu di sini, pola desain OOP klasik adalah beberapa di antaranya. Secara umum, kami menentukan kait di mana kode pengguna dapat dengan aman menyambungkan ke perpustakaan dan menambahkan fungsionalitas.
Hanya membuat setiap metode publik atau memungkinkan setiap kelas untuk subklas tidak cukup untuk mencapai ekstensibilitas. Pertama-tama, sangat sulit untuk memperluas perpustakaan jika tidak jelas di mana pengguna dapat menghubungkan ke perpustakaan. Misalnya, mengganti sebagian besar metode tidak aman karena metode kelas dasar ditulis dengan asumsi implisit. Anda benar-benar perlu merancang untuk diperpanjang.
Lebih penting lagi, begitu sesuatu menjadi bagian dari API publik, Anda tidak dapat mengambilnya kembali. Anda tidak dapat melakukan refactor tanpa merusak kode hilir. Keterbukaan prematur membatasi perpustakaan ke desain yang kurang optimal. Sebaliknya, menjadikan barang-barang internal sebagai hal pribadi tetapi menambahkan kait jika nanti dibutuhkan untuk mereka adalah pendekatan yang lebih aman. Meskipun itu adalah cara yang waras untuk mengatasi evolusi jangka panjang sebuah perpustakaan, ini tidak memuaskan bagi pengguna yang perlu menggunakan perpustakaan saat ini .
Jadi, apa yang terjadi? Jika ada rasa sakit yang signifikan dengan keadaan perpustakaan saat ini, pengembang dapat mengambil semua pengetahuan tentang kasus penggunaan aktual yang terakumulasi dari waktu ke waktu, dan menulis Versi 2 dari perpustakaan. Itu akan luar biasa! Ini akan memperbaiki semua bug yang ada di desain! Ini juga akan memakan waktu lebih lama dari yang diharapkan, dalam banyak kasus gagal. Dan jika versi baru sangat berbeda dengan versi lama, mungkin sulit untuk mendorong pengguna untuk bermigrasi. Anda kemudian tetap mempertahankan dua versi yang tidak kompatibel.
sumber
Setiap kelas / metode publik dan dapat dikembangkan adalah bagian dari API Anda yang harus didukung. Membatasi yang ditetapkan ke subset yang wajar dari perpustakaan memungkinkan stabilitas yang paling dan membatasi jumlah hal yang bisa salah. Ini adalah keputusan manajemen (dan bahkan proyek OSS dikelola sampai tingkat tertentu) berdasarkan pada apa yang dapat Anda dukung secara wajar.
Perbedaan antara OSS dan sumber tertutup adalah bahwa kebanyakan orang berusaha membuat dan menumbuhkan komunitas di sekitar kode sehingga lebih dari satu orang yang memelihara perpustakaan. Yang mengatakan, ada sejumlah alat manajemen yang tersedia:
Dalam proyek yang matang, apa yang akan Anda lihat adalah sesuatu seperti ini:
Pada saat itu, jika perubahan diterima tetapi pengguna ingin mempercepatnya diperbaiki, mereka dapat melakukan pekerjaan dan mengirimkan permintaan tarik atau tambalan (tergantung pada alat kontrol versi).
Tidak ada API yang statis. Namun pertumbuhan itu harus dibentuk dalam beberapa cara. Dengan menjaga segala sesuatu ditutup sampai ada kebutuhan yang diperlihatkan untuk membuka sesuatu, Anda menghindari reputasi kereta yang tidak stabil.
sumber
Saya akan menulis ulang tanggapan saya karena tampaknya itu membuatku kesal dengan beberapa orang.
visibilitas properti kelas / metode tidak ada hubungannya dengan keamanan atau keterbukaan sumber.
Alasan mengapa visibilitas ada, adalah karena objek rentan terhadap 4 masalah spesifik:
Jika Anda membuat modul Anda tidak terbungkus, maka pengguna Anda akan terbiasa mengubah status modul secara langsung. Ini berfungsi dengan baik di lingkungan utas tunggal, tetapi begitu Anda bahkan berpikir tentang menambahkan utas; Anda akan dipaksa untuk membuat negara menjadi privat dan menggunakan kunci / monitor bersama dengan getter dan setter yang membuat utas lain menunggu sumber daya, alih-alih berlomba dengannya. Ini berarti program pengguna Anda tidak akan berfungsi lagi karena variabel pribadi tidak dapat diakses dengan cara konvensional. Ini bisa berarti Anda membutuhkan banyak penulisan ulang.
Yang benar adalah bahwa lebih mudah untuk membuat kode dengan runtime tunggal dalam pikiran, dan kata kunci pribadi memungkinkan Anda untuk menambahkan kata kunci yang disinkronkan, atau beberapa kunci, dan kode pengguna Anda tidak akan rusak jika Anda merangkumnya dari awal. .
Setiap objek memiliki banyak hal yang diperlukan untuk menjadi kenyataan agar berada dalam keadaan konsisten. Sayangnya, hal-hal ini hidup di ruang yang terlihat klien karena mahal untuk memindahkan setiap objek ke prosesnya sendiri dan berbicara dengannya melalui pesan. Ini berarti bahwa sangat mudah bagi sebuah objek untuk crash keseluruhan program jika pengguna memiliki visibilitas penuh.
Ini tidak dapat dihindari, tetapi Anda dapat mencegah secara tidak sengaja menempatkan suatu objek ke kondisi tidak konsisten dengan membuat penutupan antarmuka atas layanannya yang mencegah crash tidak disengaja dengan hanya memungkinkan pengguna untuk berinteraksi dengan keadaan objek melalui antarmuka yang dibuat dengan cermat yang membuat program jauh lebih kuat . Ini tidak berarti pengguna tidak dapat dengan sengaja merusak invarian, tetapi jika mereka melakukannya, itu adalah klien mereka yang macet, yang harus mereka lakukan adalah me-restart program (data yang ingin Anda lindungi tidak boleh disimpan di sisi klien ).
Contoh bagus lainnya di mana Anda dapat meningkatkan kegunaan modul Anda adalah menjadikan konstruktor sebagai pribadi; karena jika konstruktor melempar pengecualian, itu akan mematikan program. Salah satu pendekatan malas untuk menyelesaikan ini adalah membuat konstruktor membuat kesalahan waktu kompilasi Anda bahwa Anda tidak dapat membangunnya kecuali itu dalam blok try / catch. Dengan menjadikan konstruktor sebagai pribadi, dan menambahkan metode pembuatan statis publik, Anda dapat membuat null buat metode jika gagal membuatnya, atau menggunakan fungsi panggil balik untuk menangani kesalahan, membuat program lebih ramah pengguna.
Banyak kelas memiliki banyak status dan metode dan mudah kewalahan mencoba menggulirnya; Banyak dari metode ini hanyalah noise visual seperti fungsi helper, state. membuat variabel dan metode pribadi membantu mengurangi polusi ruang lingkup dan membuatnya lebih mudah bagi pengguna untuk menemukan layanan yang mereka cari.
Intinya, ini memungkinkan Anda untuk pergi dengan memiliki fungsi pembantu di dalam kelas daripada di luar kelas; tanpa kontrol visibilitas tanpa mengganggu pengguna dengan sekelompok layanan yang seharusnya tidak pernah digunakan pengguna, sehingga Anda bisa lolos dengan memecah metode menjadi banyak metode pembantu (meskipun itu masih akan mencemari ruang lingkup Anda, tetapi bukan pengguna).
Antarmuka yang dibuat dengan baik dapat menyembunyikan basis data internal / windows / pencitraan yang tergantung pada untuk melakukan tugasnya, dan jika Anda ingin mengubah ke database lain / sistem windowing lain / perpustakaan pencitraan lain, Anda dapat menjaga antarmuka yang sama dan pengguna tidak akan memperhatikan.
Di sisi lain, jika Anda tidak melakukan ini, Anda dapat dengan mudah jatuh ke dalam membuatnya tidak mungkin untuk mengubah dependensi Anda, karena mereka terbuka, dan kode bergantung padanya. Dengan sistem yang cukup besar, biaya migrasi menjadi tidak terjangkau, sedangkan enkapsulasi dapat melindungi pengguna klien yang berperilaku baik dari keputusan masa depan untuk menukar ketergantungan.
sumber