Saya memahami konsep suatu objek, dan sebagai programmer Java saya merasakan paradigma OO datang secara alami kepada saya dalam praktiknya.
Namun baru-baru ini saya mendapati diri saya berpikir:
Tunggu sebentar, apa sebenarnya manfaat praktis menggunakan objek daripada menggunakan kelas statis (dengan enkapsulasi dan praktik OO yang tepat)?
Saya bisa memikirkan dua manfaat menggunakan objek (keduanya signifikan dan kuat):
Polimorfisme: memungkinkan Anda untuk menukar fungsionalitas secara dinamis dan fleksibel selama runtime. Juga memungkinkan untuk menambahkan 'bagian' fungsionalitas baru dan alternatifnya ke sistem dengan mudah. Misalnya jika ada
Car
kelas yang dirancang untuk bekerja denganEngine
objek, dan Anda ingin menambahkan Mesin baru ke sistem yang dapat digunakan oleh Mobil, Anda dapat membuatEngine
subkelas baru dan cukup mengirimkan objek kelas ini keCar
objek, tanpa harus ubah apa saja tentangCar
. Dan Anda dapat memutuskan untuk melakukannya selama runtime.Mampu 'menyampaikan fungsionalitas': Anda dapat melewatkan objek di sekitar sistem secara dinamis.
Tetapi apakah ada lebih banyak keuntungan pada objek dibandingkan kelas statis?
Seringkali ketika saya menambahkan 'bagian' baru ke sistem, saya melakukannya dengan membuat kelas baru dan membuat objek dari itu.
Tetapi baru-baru ini ketika saya berhenti dan memikirkannya, saya menyadari bahwa kelas statis akan melakukan hal yang sama dengan objek, di banyak tempat di mana saya biasanya menggunakan objek.
Misalnya, saya sedang berupaya menambahkan mekanisme simpan / muat-file ke aplikasi saya.
Dengan sebuah objek, baris kode panggilan akan terlihat seperti ini: Thing thing = fileLoader.load(file);
Dengan kelas statis, akan terlihat seperti ini: Thing thing = FileLoader.load(file);
Apa bedanya?
Cukup sering saya tidak bisa memikirkan alasan untuk membuat instance objek ketika kelas statis lama-polos akan bertindak sama. Tetapi dalam sistem OO, kelas statis cukup langka. Jadi saya pasti kehilangan sesuatu.
Apakah ada lebih banyak manfaat untuk objek selain dari dua yang saya daftarkan? Tolong jelaskan.
EDIT: Untuk memperjelas. Saya menemukan benda sangat berguna ketika bertukar fungsionalitas, atau meneruskan data. Misalnya saya menulis aplikasi yang membuat melodi. MelodyGenerator
memiliki beberapa subclass yang membuat melodi secara berbeda, dan objek dari kelas-kelas ini dapat dipertukarkan (pola Strategi).
Melodi juga objek, karena berguna untuk menyebarkannya. Begitu juga dengan Chords and Scales.
Tetapi bagaimana dengan bagian 'statis' dari sistem - yang tidak akan diedarkan? Misalnya - mekanisme 'simpan file'. Mengapa saya harus mengimplementasikannya dalam objek, dan bukan kelas statis?
sumber
Thing
?FileLoader
baca dari soket? Atau tiruan untuk pengujian? Atau yang membuka file zip?System.Math
di .NET adalah contoh dari sesuatu yang jauh lebih masuk akal sebagai kelas statis: Anda tidak akan perlu menukar atau mengejeknya dan tidak ada operasi yang secara logis dapat menjadi bagian dari instance. Saya benar-benar tidak berpikir contoh 'menabung' Anda sesuai dengan tagihan itu.Jawaban:
lol Anda terdengar seperti tim yang dulu pernah saya kerjakan;)
Java (dan mungkin C #) tentu mendukung gaya pemrograman itu. Dan saya bekerja dengan orang-orang yang insting pertamanya adalah, "Saya bisa menjadikannya metode statis!" Tetapi ada beberapa biaya halus yang mengejar Anda dari waktu ke waktu.
1) Java adalah bahasa yang Berorientasi Objek. Dan itu mendorong orang-orang fungsional kacang, tetapi benar-benar memegang cukup baik. Gagasan di balik OO adalah bundling fungsionalitas dengan keadaan untuk memiliki unit kecil data dan fungsionalitas yang mempertahankan semantiknya dengan menyembunyikan keadaan dan hanya memaparkan fungsi yang masuk akal dalam konteks itu.
Dengan pindah ke kelas dengan metode statis saja, Anda melanggar bagian "state" dari persamaan. Tetapi negara masih harus tinggal di suatu tempat. Jadi apa yang saya lihat dari waktu ke waktu adalah bahwa kelas dengan semua metode statis mulai memiliki daftar parameter yang semakin rumit, karena statusnya bergerak dari kelas dan masuk ke pemanggilan fungsi.
Setelah Anda membuat kelas dengan semua metode statis, jalankan dan hanya survei berapa banyak metode yang memiliki parameter tunggal yang umum. Ini adalah petunjuk bahwa parameter harus menjadi kelas yang mengandung fungsi-fungsi tersebut, atau parameter itu harus menjadi atribut dari instance.
2) Aturan untuk OO cukup dipahami. Setelah beberapa saat, Anda dapat melihat desain kelas dan melihat apakah itu memenuhi kriteria seperti SOLID. Dan setelah banyak pengujian unit praktik, Anda mengembangkan pemahaman yang baik tentang apa yang membuat kelas "berukuran tepat" dan "koheren". Tetapi tidak ada aturan yang baik untuk sebuah kelas dengan semua metode statis, dan tidak ada alasan nyata mengapa Anda tidak harus menggabungkan semua yang ada di sana. Kelas terbuka di editor Anda, jadi apa-apaan ini? Cukup tambahkan metode baru Anda di sana. Setelah beberapa saat, aplikasi Anda berubah menjadi sejumlah "Objek Dewa" yang bersaing, masing-masing berusaha untuk mendominasi dunia. Sekali lagi, refactoring mereka menjadi unit yang lebih kecil sangat subjektif dan sulit untuk mengatakan apakah Anda sudah benar.
3) Antarmuka adalah salah satu fitur paling kuat di Jawa. Warisan kelas telah terbukti bermasalah, tetapi pemrograman dengan antarmuka tetap menjadi salah satu trik bahasa yang paling kuat. (lagi ke C #) Semua kelas statis tidak dapat menempatkan diri mereka ke dalam model itu.
4) Ini membanting pintu pada teknik OO penting yang tidak dapat Anda manfaatkan. Jadi, Anda dapat bekerja selama bertahun-tahun hanya dengan palu di kotak peralatan Anda, tanpa menyadari betapa lebih mudahnya jika Anda memiliki obeng juga.
4.5) Ini menciptakan dependensi waktu kompilasi yang paling sulit, paling tidak bisa dipecahkan. Jadi, misalnya jika Anda memilikinya
FileSystem.saveFile()
maka tidak ada cara untuk mengubahnya, kecuali memalsukan JVM Anda saat run time. Yang berarti bahwa setiap kelas yang mereferensikan kelas fungsi statis Anda memiliki ketergantungan, waktu kompilasi yang sulit pada implementasi spesifik itu, yang membuat ekstensi hampir tidak mungkin, dan sangat menyulitkan pengujian. Anda dapat menguji kelas statis secara terpisah, tetapi menjadi sangat sulit untuk menguji kelas yang merujuk ke kelas itu secara terpisah.5) Anda akan membuat rekan kerja Anda gila. Sebagian besar profesional yang bekerja dengan saya menganggap serius kode mereka, dan memperhatikan setidaknya beberapa tingkat prinsip desain. Mengesampingkan maksud inti dari suatu bahasa akan membuat mereka mencabut rambut mereka karena mereka akan terus-menerus memperbaiki kode.
Ketika saya dalam bahasa, saya selalu mencoba menggunakan bahasa dengan baik. Jadi, misalnya, ketika saya berada di Jawa, saya menggunakan desain OO yang bagus, karena dengan begitu saya benar-benar memanfaatkan bahasa untuk apa fungsinya. Ketika saya menggunakan Python, saya mencampur fungsi tingkat modul dengan kelas sesekali - saya hanya bisa menulis kelas dengan Python, tapi kemudian saya pikir saya tidak akan menggunakan bahasa untuk apa yang baik.
Taktik lain adalah menggunakan bahasa dengan buruk, dan mereka mengeluh tentang semua masalah yang disebabkannya. Tapi itu berlaku untuk hampir semua teknologi.
Fitur utama Java adalah mengelola kompleksitas dalam unit-unit kecil yang dapat diuji yang saling menggantung sehingga mudah dipahami. Java menekankan definisi antarmuka yang jelas terlepas dari implementasi - yang merupakan manfaat besar. Itu sebabnya (dan bahasa OO serupa lainnya) tetap digunakan secara luas. Untuk semua verbositas dan ritualisme, ketika saya selesai dengan aplikasi Java besar, saya selalu merasa ide-ide lebih bersih dipisahkan dalam kode daripada proyek saya dalam bahasa yang lebih dinamis.
Tapi itu sulit. Saya telah melihat orang-orang mendapatkan bug "semua statis", dan agak sulit untuk mengeluarkannya. Tetapi saya telah melihat mereka memiliki perasaan lega yang besar ketika mereka mengatasinya.
sumber
Kamu bertanya:
Sebelum pertanyaan ini, Anda mencantumkan Polimorfisme dan diedarkan sebagai dua manfaat menggunakan Objek. Saya ingin mengatakan bahwa itu adalah fitur dari paradigma OO. Enkapsulasi adalah fitur lain dari paradigma OO.
Namun, itu bukan manfaatnya. Manfaatnya adalah:
Kamu berkata:
Saya pikir Anda memiliki poin yang valid di sana. Pada intinya, pemrograman tidak lain adalah transformasi data dan penciptaan efek samping berdasarkan data. Terkadang mengubah data membutuhkan data tambahan. Di lain waktu, tidak.
Ketika Anda berurusan dengan kategori pertama dari transformasi, data tambahan harus dimasukkan sebagai input atau disimpan di suatu tempat. Objek adalah pendekatan yang lebih baik daripada kelas statis untuk transformasi semacam itu. Objek dapat menyimpan data tambahan dan menggunakannya pada waktu yang tepat.
Untuk kategori kedua dari transformasi, kelas statis sama baiknya dengan Obyek, jika tidak lebih baik. Fungsi matematika adalah contoh klasik dari kategori ini. Sebagian besar fungsi pustaka C standar termasuk dalam kategori ini juga.
Kamu bertanya:
Jika
FileLoader
tidak, pernah , perlu menyimpan data apa pun, saya akan pergi dengan pendekatan kedua. Jika ada sedikit peluang bahwa itu akan membutuhkan data tambahan untuk melakukan operasi, pendekatan pertama adalah taruhan yang lebih aman.Kamu bertanya:
Saya membuat daftar manfaat (keuntungan) menggunakan paradigma OO. Saya harap mereka cukup jelas. Jika tidak, saya akan senang menjelaskannya.
Kamu bertanya:
Ini adalah contoh di mana kelas statis tidak akan dilakukan. Ada banyak cara untuk menyimpan data aplikasi Anda ke file:
Satu-satunya cara untuk menyediakan opsi tersebut adalah dengan membuat Antarmuka dan membuat Objek yang mengimplementasikan antarmuka.
Kesimpulannya
Gunakan pendekatan yang tepat untuk masalah yang dihadapi. Lebih baik tidak beragama tentang satu pendekatan vs yang lain.
sumber
Melody
,Chord
,Improvisations
,SoundSample
dan lain-lain), maka akan ekonomis untuk menyederhanakan pelaksanaan melalui abstraksi.Itu tergantung pada bahasa dan konteksnya, kadang-kadang. Misalnya,
PHP
skrip yang digunakan untuk melayani permintaan selalu memiliki satu permintaan untuk layanan dan satu respons untuk dihasilkan sepanjang masa pakai skrip, sehingga metode statis untuk bertindak atas permintaan dan menghasilkan respons mungkin tepat. Tetapi dalam server yang ditulisNode.js
, mungkin ada banyak permintaan dan tanggapan yang berbeda pada saat yang bersamaan. Jadi pertanyaan pertama adalah - apakah Anda yakin bahwa kelas statis benar-benar sesuai dengan objek tunggal?Kedua, bahkan jika Anda memiliki lajang, menggunakan objek memungkinkan Anda untuk mengambil keuntungan dari polimorfisme menggunakan teknik seperti Dependency_injection dan Factory_method_pattern . Ini sering digunakan dalam berbagai pola Inversion_of_control , dan berguna untuk membuat objek tiruan untuk pengujian, pencatatan, dll.
Anda menyebutkan keuntungan di atas, jadi di sini adalah salah satu yang tidak Anda dapatkan: warisan. Banyak bahasa tidak memiliki kemampuan untuk menimpa metode statis dengan cara yang sama seperti metode instance dapat ditimpa. Secara umum, jauh lebih sulit untuk mewarisi dan mengganti metode statis.
sumber
Selain posting Rob Y
Selama fungsionalitas Anda
load(File file)
dapat dipisahkan dengan jelas dari semua fungsi lain yang Anda gunakan, boleh saja menggunakan metode / kelas statis. Anda mengeksternalisasi keadaan (yang bukan hal buruk) dan Anda juga tidak mendapatkan redundansi seperti yang Anda dapat misalnya menerapkan sebagian atau menjelajah fungsi Anda sehingga Anda tidak perlu mengulangi sendiri. (yang sebenarnya sama atau mirip dengan menggunakanfactory
pola)Namun, begitu dua fungsi ini mulai memiliki penggunaan umum, Anda ingin dapat mengelompokkannya. Bayangkan Anda tidak hanya memiliki
load
fungsi tetapi jugahasValidSyntax
fungsi. Apa yang akan kamu lakukan?Lihat dua referensi di
myfile
sini? Anda mulai mengulangi diri Anda sendiri karena kondisi eksternal Anda harus dilewati untuk setiap panggilan. Rob Y telah menjelaskan bagaimana Anda menginternalisasi negara (di sinifile
) sehingga Anda dapat melakukannya seperti ini:sumber
hasValidSyntax()
danload()
tidak diizinkan untuk menggunakan kembali keadaan (hasil dari file yang diurai sebagian).Masalah utama ketika menggunakan kelas statis adalah mereka memaksa Anda untuk menyembunyikan dependensi Anda, dan memaksa Anda untuk bergantung pada implementasi. Dalam tanda tangan konstruktor berikut, apa dependensi Anda:
Nah, kalau dilihat dari tanda tangan, seseorang hanya perlu nama, kan? Ya, tidak jika implementasinya adalah:
Jadi seseorang tidak hanya dipakai. Kami benar-benar menarik data dari database, yang memberi kami jalur ke file, yang kemudian harus diuraikan, dan kemudian data nyata yang kami inginkan harus dihapus. Contoh ini jelas di atas, tetapi membuktikan intinya. Tapi tunggu, masih ada banyak lagi! Saya menulis tes berikut:
Ini harus berlalu, kan? Maksudku, kita merangkum semua hal lainnya, kan? Yah, sebenarnya itu meledak dengan pengecualian. Mengapa? Oh, ya, dependensi tersembunyi yang tidak kita ketahui memiliki keadaan global. The
DBConnection
kebutuhan diinisialisasi dan terhubung. TheFileLoader
kebutuhan diinisialisasi denganFileFormat
objek (sepertiXMLFileFormat
atauCSVFileFormat
). Belum pernah dengar itu? Nah, itu intinya. Kode Anda (dan kompiler Anda) tidak dapat memberi tahu Anda bahwa Anda memerlukan hal-hal ini karena panggilan statis menyembunyikan dependensi tersebut. Apakah saya mengatakan tes? Maksud saya, pengembang junior yang baru saja mengirimkan sesuatu seperti ini di rilis terbaru Anda. Lagi pula, kompilasi = berfungsi, kan?Selain itu, katakan Anda menggunakan sistem yang tidak memiliki instance MySQL yang sedang berjalan. Atau, katakan Anda menggunakan sistem Windows tetapi
DBConnection
kelas Anda hanya keluar ke server MySQL Anda pada kotak Linux (dengan jalur Linux). Atau, katakan Anda berada di sistem di mana jalur yang dikembalikan olehDBConnection
tidak membaca / menulis untuk Anda. Itu berarti bahwa mencoba menjalankan atau menguji sistem ini di bawah salah satu kondisi ini akan gagal, bukan karena kesalahan kode, tetapi karena kesalahan desain yang membatasi fleksibilitas kode dan mengikat Anda ke suatu implementasi.Sekarang, katakanlah, kami ingin mencatat setiap panggilan ke database untuk satu
Person
contoh spesifik , yang melewati jalur tertentu yang merepotkan. Kita dapat memasukkan logging ke dalamDBConnection
, tetapi ini akan mencatat semuanya , meletakkan banyak kekacauan dan membuatnya sulit untuk membedakan jalur kode tertentu yang ingin kita lacak. Namun, jika kita menggunakan injeksi ketergantungan dengan sebuahDBConnection
instance, kita bisa mengimplementasikan antarmuka dalam dekorator (atau memperluas kelas, karena kita memiliki kedua opsi yang tersedia dengan objek). Dengan kelas statis, kami tidak dapat menyuntikkan dependensi, kami tidak dapat mengimplementasikan antarmuka, kami tidak dapat membungkusnya dalam dekorator, dan kami tidak dapat memperluas kelas. Kami hanya dapat menyebutnya secara langsung, di suatu tempat tersembunyi jauh di dalam kode kami. Jadi kita dipaksa untuk memiliki ketergantungan tersembunyi pada suatu implementasi.Apakah ini selalu buruk? Tidak harus, tetapi mungkin lebih baik membalikkan sudut pandang Anda dan berkata, "Apakah ada alasan bagus mengapa ini tidak menjadi contoh?" daripada "Apakah ada alasan yang baik ini harus menjadi contoh?" Jika Anda benar-benar dapat mengatakan bahwa kode Anda tidak akan goyah (dan tidak memiliki kewarganegaraan) seperti
Math.abs()
, baik dalam implementasinya maupun cara penggunaannya, maka Anda dapat mempertimbangkan untuk membuatnya statis. Namun, memiliki instance atas kelas statis, memberi Anda dunia fleksibilitas yang tidak selalu mudah untuk ditangkap kembali setelah fakta. Ini juga dapat memberi Anda lebih banyak kejelasan tentang sifat sebenarnya dari dependensi kode Anda.sumber
new
mengumpulkan banyak objek di konstruktor (yang umumnya tidak disarankan), tetapi saya juga dapat menyuntikkannya. Dengan kelas statis, tidak ada cara untuk menyuntikkannya (tidak mudah di Jawa, dan itu akan menjadi diskusi lain untuk bahasa yang memungkinkan itu), jadi tidak ada pilihan. Itu sebabnya saya menyoroti gagasan dipaksa menjadi sangat tergantung pada jawaban saya.Class
, maka kami memastikan itu adalah kelas yang tepat) atau Anda mengetik bebek (kami memastikan itu menanggapi metode yang tepat). Jika Anda ingin melakukan yang terakhir, maka Anda harus mengevaluasi kembali pilihan bahasa Anda. Jika Anda ingin melakukan yang pertama, instans baik-baik saja dan dibangun.Hanya dua sen saya.
Untuk pertanyaan Anda:
Anda dapat bertanya pada diri sendiri apakah mekanisme bagian dari sistem yang memutar suara, atau bagian dari sistem yang menyimpan data ke file AKAN MENGUBAH . Jika jawaban Anda adalah ya, itu menunjukkan bahwa Anda harus mengabstraksi mereka menggunakan
abstract class
/interface
. Anda mungkin bertanya, bagaimana saya bisa mengetahui hal-hal di masa depan? Jelas, kita tidak bisa. Jadi, jika masalahnya stateless, Anda dapat menggunakan 'kelas statis' sepertijava.lang.Math
, jika tidak, gunakan pendekatan berorientasi objek.sumber