Jika objek abadiut bagus, sederhana dan menawarkan manfaat dalam pemrograman bersamaan, mengapa programmer terus membuat objek yang bisa berubah²?
Saya memiliki empat tahun pengalaman dalam pemrograman Java dan seperti yang saya lihat, hal pertama yang dilakukan orang setelah membuat kelas adalah menghasilkan getter dan setter dalam IDE (sehingga membuatnya bisa berubah). Apakah ada kesadaran yang kurang atau bisakah kita menggunakan benda-benda yang bisa berubah dalam kebanyakan skenario?
¹ objek Berubah adalah obyek yang negara tidak dapat diubah setelah dibuat.
² Objek yang dapat berubah-ubah adalah objek yang dapat dimodifikasi setelah dibuat.
object-oriented
immutability
ahsteele
sumber
sumber
Jawaban:
Kedua objek yang dapat berubah dan tidak berubah memiliki kegunaan, pro dan kontra sendiri.
Benda-benda yang tidak dapat berubah memang membuat hidup lebih sederhana dalam banyak kasus. Mereka terutama berlaku untuk tipe nilai, di mana objek tidak memiliki identitas sehingga mereka dapat dengan mudah diganti. Dan mereka dapat membuat pemrograman bersamaan lebih aman dan bersih (kebanyakan bug konkurensi yang paling sulit ditemukan pada akhirnya disebabkan oleh keadaan yang bisa berubah yang dibagikan di antara utas). Namun, untuk objek besar dan / atau kompleks, membuat salinan objek baru untuk setiap perubahan tunggal bisa sangat mahal dan / atau membosankan. Dan untuk objek dengan identitas berbeda, mengubah objek yang sudah ada jauh lebih sederhana dan intuitif daripada membuat salinannya yang baru dan dimodifikasi.
Pikirkan tentang karakter permainan. Dalam gim, kecepatan adalah prioritas utama, jadi mewakili karakter gim Anda dengan objek yang bisa berubah kemungkinan besar akan membuat gim Anda berjalan secara signifikan lebih cepat daripada implementasi alternatif tempat salinan baru gim karakter dihasilkan untuk setiap perubahan kecil.
Selain itu, persepsi kita tentang dunia nyata tak terhindarkan didasarkan pada objek yang bisa berubah. Ketika Anda mengisi mobil Anda dengan bahan bakar di pompa bensin, Anda menganggapnya sebagai objek yang sama selama ini (yaitu identitasnya dipertahankan ketika kondisinya berubah) - tidak seolah-olah mobil tua dengan tangki kosong diganti dengan yang baru berturut-turut contoh mobil memiliki tangki mereka secara bertahap semakin penuh. Jadi, setiap kali kita memodelkan beberapa domain dunia nyata dalam suatu program, biasanya lebih mudah dan lebih mudah untuk menerapkan model domain menggunakan objek yang bisa berubah untuk mewakili entitas dunia nyata.
Terlepas dari semua alasan yang sah ini, sayangnya, penyebab paling mungkin mengapa orang terus membuat objek yang bisa berubah adalah kelembaman pikiran, alias penolakan untuk berubah. Perhatikan bahwa sebagian besar pengembang saat ini telah dilatih sebelum kekekalan (dan paradigma yang mengandung, pemrograman fungsional) menjadi "trendi" dalam lingkup pengaruhnya, dan tidak memperbarui pengetahuan mereka tentang alat dan metode baru dalam perdagangan kami - pada kenyataannya, banyak dari kita manusia yang secara positif menentang ide dan proses baru. "Saya telah pemrograman seperti ini selama nn tahun dan saya tidak peduli tentang mode bodoh terbaru!"
sumber
Point
kelas di NET misalnya adalah kekal tetapi menciptakan poin baru sebagai hasil dari perubahan mudah dan dengan demikian terjangkau. Animasi karakter yang tidak dapat diubah dapat dibuat sangat murah dengan memisahkan “bagian yang bergerak” (tapi ya, beberapa aspek kemudian dapat berubah). (2) "objek besar dan / atau kompleks" dapat berubah dengan sangat baik. String sering kali berukuran besar, dan biasanya mendapat manfaat dari kekekalan. Saya pernah menulis ulang kelas grafik yang kompleks agar tidak berubah, membuat kode lebih sederhana dan lebih efisien. Dalam kasus seperti itu, memiliki pembangun yang bisa berubah adalah kuncinya.Saya pikir Anda semua melewatkan jawaban yang paling jelas. Sebagian besar pengembang membuat objek yang dapat diubah karena mutabilitas adalah default dalam bahasa imperatif. Sebagian besar dari kita memiliki hal-hal yang lebih baik untuk dilakukan dengan waktu kita daripada terus-menerus mengubah kode dari default - lebih benar atau tidak. Dan ketidakberdayaan bukanlah obat mujarab seperti pendekatan lainnya. Itu membuat beberapa hal lebih mudah tetapi membuat orang lain jauh lebih sulit karena beberapa jawaban telah ditunjukkan.
sumber
final
,const
dll memerlukan sedikit usaha ekstra ... kecuali jika Anda membuat template kode :-)Ada tempat untuk berubah-ubah. Prinsip-prinsip desain yang didorong oleh domain memberikan pemahaman yang kuat tentang apa yang harus bisa berubah dan apa yang harus tidak berubah. Jika Anda memikirkannya, Anda akan menyadari bahwa tidak praktis untuk membayangkan suatu sistem di mana setiap perubahan keadaan menjadi suatu objek memerlukan penghancuran dan komposisi ulang dari itu, dan untuk setiap objek yang mereferensikannya. Dengan sistem yang kompleks, hal ini dapat dengan mudah menyapu dan membangun kembali seluruh objek grafik sistem
Sebagian besar pengembang tidak membuat apa pun di mana persyaratan kinerja cukup signifikan sehingga mereka perlu fokus pada konkurensi (atau banyak masalah lain yang secara universal dianggap sebagai praktik yang baik oleh informasi).
Ada beberapa hal yang tidak bisa Anda lakukan dengan objek abadi, seperti memiliki hubungan dua arah. Setelah Anda menetapkan nilai asosiasi pada satu objek, itu akan berubah identitas. Jadi, Anda menetapkan nilai baru pada objek lain dan juga berubah. Masalahnya adalah referensi objek pertama tidak lagi valid, karena instance baru telah dibuat untuk mewakili objek dengan referensi. Melanjutkan ini hanya akan menghasilkan regresi tanpa batas. Saya melakukan sedikit studi kasus setelah membaca pertanyaan Anda, begini tampilannya. Apakah Anda memiliki pendekatan alternatif yang memungkinkan fungsi seperti itu sambil mempertahankan keabadian?
sumber
Relationship(a, b)
; pada titik menciptakan hubungan, kedua entitasa
&b
sudah ada, dan hubungan itu sendiri juga tidak berubah. Saya tidak mengatakan pendekatan ini praktis di Jawa; Hanya saja itu mungkin.R
adalahRelationship(a,b)
dan keduanyaa
danb
tidak berubah, tidaka
juga tidakb
akan memiliki referensiR
. Agar ini berfungsi, referensi harus disimpan di tempat lain (seperti kelas statis). Apakah saya memahami maksud Anda dengan benar?Saya telah membaca "struktur data murni fungsional", dan itu membuat saya menyadari bahwa ada beberapa struktur data yang jauh lebih mudah diimplementasikan dengan menggunakan objek yang bisa berubah.
Untuk menerapkan pohon pencarian biner, Anda harus mengembalikan pohon baru setiap kali: Pohon baru Anda harus membuat salinan dari setiap node yang telah dimodifikasi (cabang-cabang yang tidak dimodifikasi dibagikan). Untuk fungsi insert Anda ini tidak terlalu buruk, tetapi bagi saya, banyak hal menjadi tidak efisien dengan cepat ketika saya mulai bekerja pada delete dan re-balance.
Hal lain yang perlu disadari adalah bahwa Anda dapat bertahun-tahun menulis kode berorientasi objek, dan tidak pernah benar-benar menyadari betapa buruknya keadaan yang dapat ditukar yang dibagikan, jika kode Anda tidak dijalankan dengan cara yang akan memunculkan masalah konkurensi.
sumber
Dari sudut pandang saya, itu adalah kurangnya kesadaran. Jika Anda melihat bahasa JVM lain yang dikenal (Scala, Clojure), objek yang bisa berubah jarang terlihat dalam kode dan itulah sebabnya orang mulai menggunakannya dalam skenario di mana threading tunggal tidak cukup.
Saat ini saya sedang belajar Clojure dan memiliki sedikit pengalaman dalam Scala (4 tahun + di Jawa juga) dan gaya pengkodean Anda berubah karena kesadaran negara.
sumber
Saya pikir salah satu faktor utama telah diabaikan: Java Beans sangat bergantung pada gaya tertentu dari bermutasi objek, dan (terutama mengingat sumber) beberapa orang tampaknya menganggap itu sebagai (atau bahkan yang ) contoh kanonik bagaimana semua Java harus ditulis.
sumber
Setiap sistem Java perusahaan yang saya kerjakan dalam karier saya menggunakan Hibernate atau Java Persistence API (JPA). Hibernate dan JPA pada dasarnya menentukan bahwa sistem Anda menggunakan objek yang bisa berubah, karena seluruh premisnya adalah mereka mendeteksi dan menyimpan perubahan pada objek data Anda. Bagi banyak proyek, kemudahan pengembangan yang dibawa Hibernate lebih menarik daripada manfaat objek yang tidak dapat diubah.
Jelas objek yang bisa berubah telah ada jauh lebih lama dari Hibernate, jadi Hibernate mungkin bukan 'penyebab' asli dari popularitas objek yang bisa berubah. Mungkin popularitas objek yang dapat diubah memungkinkan Hibernate berkembang.
Tapi hari ini jika banyak programmer junior memotong gigi mereka pada sistem perusahaan menggunakan Hibernate atau ORM lain maka mungkin mereka akan mengambil kebiasaan menggunakan objek yang bisa berubah. Kerangka kerja seperti Hibernate mungkin membudaya popularitas objek yang bisa berubah.
sumber
Poin utama yang belum disebutkan adalah bahwa keadaan suatu objek bisa berubah memungkinkan untuk memiliki identitas objek yang merangkum keadaan itu menjadi abadi.
Banyak program dirancang untuk memodelkan hal-hal dunia nyata yang secara inheren bisa berubah. Misalkan pada pukul 12.51 pagi, beberapa variabel
AllTrucks
memegang referensi ke objek # 451, yang merupakan akar dari struktur data yang menunjukkan kargo apa yang terkandung dalam semua truk armada pada saat itu (12:51 pagi), dan beberapa variabelBobsTruck
dapat digunakan untuk mendapatkan referensi ke objek # 24601 menunjuk ke objek yang menunjukkan kargo apa yang terkandung dalam truk Bob pada saat itu (12:51 pagi). Pada pukul 12:52 pagi, beberapa truk (termasuk Bob) dimuat dan dibongkar, dan struktur data diperbarui sehinggaAllTrucks
sekarang akan memiliki referensi ke struktur data yang menunjukkan muatan berada di semua truk pada pukul 12:52.Apa yang harus terjadi
BobsTruck
?Jika properti 'kargo' dari setiap objek truk tidak dapat diubah, maka objek # 24601 akan selamanya mewakili keadaan yang dimiliki truk Bob pada pukul 12:51 pagi. Jika
BobsTruck
memegang referensi langsung ke objek # 24601, maka kecuali kode pembaruan yangAllTrucks
juga terjadi untuk memperbaruiBobsTruck
, itu akan berhenti mewakili keadaan truk Bob saat ini. Perhatikan lebih lanjut bahwa kecualiBobsTruck
disimpan dalam suatu bentuk objek yang dapat diubah, satu-satunya cara agar pembaruan yang diperbaruiAllTrucks
adalah jika kode diprogram secara eksplisit untuk melakukannya.Jika seseorang ingin dapat menggunakan
BobsTruck
untuk mengamati truk Bob negara sambil tetap menjaga semua benda tetap, seseorang bisaBobsTruck
menjadi fungsi abadi yang, mengingat nilai yangAllTrucks
telah atau miliki pada waktu tertentu, akan menghasilkan keadaan truk Bob di waktu itu. Satu bahkan dapat memilikinya memegang sepasang fungsi abadi - salah satunya akan seperti di atas, dan yang lainnya akan menerima referensi ke keadaan armada dan keadaan truk baru, dan mengembalikan referensi ke keadaan armada baru yang cocok dengan yang lama, kecuali bahwa truk Bob akan memiliki negara baru.Sayangnya, harus menggunakan fungsi seperti itu setiap kali seseorang ingin mengakses keadaan truk Bob bisa menjadi agak menjengkelkan dan rumit. Pendekatan alternatif akan mengatakan bahwa objek # 24601 akan selalu dan selamanya (selama orang memegang referensi untuk itu) mewakili saat keadaan truk Bob. Kode yang ingin berulang kali mengakses kondisi truk Bob saat ini tidak harus menjalankan fungsi yang menghabiskan waktu setiap kali - itu bisa dengan mudah melakukan fungsi pencarian sekali untuk mengetahui bahwa objek # 24601 adalah truk Bob, dan kemudian cukup akses objek itu kapan saja ia ingin melihat kondisi truk Bob saat ini.
Perhatikan bahwa pendekatan fungsional bukan tanpa keuntungan dalam lingkungan single-threaded, atau dalam lingkungan multi-threaded di mana thread sebagian besar hanya akan mengamati data daripada mengubahnya. Setiap pengamat utas yang menyalin referensi objek yang terkandung
AllTrucks
dan kemudian memeriksa keadaan truk yang diwakili dengan demikian akan melihat keadaan semua truk pada saat itu meraih referensi. Setiap kali utas pengamat ingin melihat data yang lebih baru, itu hanya dapat mengambil kembali referensi. Di sisi lain, memiliki seluruh keadaan armada yang diwakili oleh satu objek abadi akan menghalangi kemungkinan dua utas memperbarui truk yang berbeda secara bersamaan, karena setiap utas jika dibiarkan pada perangkatnya sendiri akan menghasilkan objek "armada negara" baru yang termasuk kondisi baru truknya dan kondisi lama lainnya. Kebenaran dapat dipastikan jika masing-masing utas menggunakanCompareExchange
untuk memperbaruiAllTrucks
hanya jika itu tidak berubah, dan menanggapi gagalCompareExchange
dengan meregenerasi objek keadaannya dan mencoba kembali operasi, tetapi jika lebih dari satu utas mencoba operasi penulisan simultan, kinerja umumnya akan lebih buruk daripada jika semua penulisan dilakukan pada satu utas; semakin banyak utas mencoba operasi simultan tersebut, semakin buruk kinerjanya.Jika objek truk individu dapat berubah tetapi memiliki identitas yang tidak dapat diubah , skenario multi-ulir menjadi lebih bersih. Hanya satu utas yang diizinkan beroperasi pada suatu waktu pada truk tertentu, tetapi utas yang beroperasi pada truk yang berbeda dapat melakukannya tanpa gangguan. Meskipun ada beberapa cara seseorang dapat meniru perilaku seperti itu bahkan ketika menggunakan objek yang tidak dapat diubah (misalnya seseorang dapat mendefinisikan objek "AllTrucks" sehingga pengaturan keadaan truk milik XXX ke SSS hanya akan memerlukan menghasilkan objek yang mengatakan "Pada [Waktu], keadaan truk milik [XXX] sekarang [SSS]; keadaan segalanya adalah [Nilai lama AllTrucks] ". Menghasilkan objek seperti itu akan cukup cepat sehingga bahkan di hadapan pertengkaran, sebuah
CompareExchange
loop tidak akan lama. Di sisi lain, menggunakan struktur data seperti itu akan secara substansial meningkatkan jumlah waktu yang dibutuhkan untuk menemukan truk orang tertentu. Menggunakan objek yang bisa berubah dengan identitas yang tidak berubah menghindari masalah itu.sumber
Tidak ada benar atau salah, itu tergantung apa yang Anda inginkan. Ada alasan mengapa beberapa orang lebih suka bahasa yang mendukung satu paradigma di atas yang lain, dan satu model data lebih dari yang lain. Itu hanya tergantung pada preferensi Anda, dan pada apa yang ingin Anda capai (dan dapat dengan mudah menggunakan kedua pendekatan tanpa mengasingkan penggemar berat dari satu sisi atau sisi lain adalah grail suci yang dicari beberapa bahasa).
Saya pikir cara terbaik dan tercepat untuk menjawab pertanyaan Anda adalah bagi Anda untuk memimpin Pro dan Kontra Kekekalan vs Mutabilitas .
sumber
Periksa posting blog ini: http://www.yegor256.com/2014/06/09/objects-should-be-immutable.html . Ini meringkas mengapa benda tidak berubah lebih baik daripada bisa berubah. Berikut daftar argumen singkat:
Orang-orang menggunakan objek yang bisa berubah, sejauh yang saya mengerti, karena mereka masih mencampurkan OOP dengan pemrograman prosedural imperatif.
sumber
Dalam Java objek yang tidak dapat diubah memerlukan konstruktor yang akan mengambil semua properti objek (atau konstruktor membuatnya dari argumen atau default lain). Properti itu harus ditandai sebagai final .
Ada empat masalah dengan ini sebagian besar berkaitan dengan pengikatan data :
Anda dapat mengurangi # 1 dan # 2 menggunakan anotasi seperti
@ConstructorProperties
dan membuat objek pembangun yang dapat berubah (biasanya fasih) untuk membuat objek yang tidak dapat diubah.sumber
Saya terkejut bahwa tidak ada yang menyebutkan manfaat optimalisasi kinerja. Bergantung pada bahasa, kompiler dapat membuat banyak optimisasi ketika berhadapan dengan data yang tidak dapat diubah karena tahu data tidak akan pernah berubah. Segala macam hal terlewati, yang memberi Anda manfaat kinerja yang luar biasa.
Juga objek yang tidak berubah hampir menghilangkan seluruh kelas bug negara.
Ini tidak sebesar yang seharusnya karena itu lebih sulit, tidak berlaku untuk setiap bahasa dan kebanyakan orang diajarkan kode imperatif.
Saya juga telah menemukan bahwa sebagian besar programmer senang dalam kotak mereka dan sering menolak ide-ide baru yang mereka tidak sepenuhnya mengerti. Secara umum orang tidak suka perubahan.
Juga ingat, bahwa keadaan kebanyakan programmer buruk. Kebanyakan pemrograman yang dilakukan di alam liar mengerikan dan disebabkan oleh kurangnya pemahaman dan politik.
sumber
Mengapa orang menggunakan fitur yang kuat? Mengapa orang menggunakan pemrograman meta, kemalasan, atau pengetikan dinamis? Jawabannya adalah kenyamanan. Keadaan yang bisa berubah sangat mudah. Sangat mudah untuk memperbarui di tempat dan ambang ukuran proyek di mana keadaan tidak berubah lebih produktif untuk bekerja dengan daripada keadaan bisa berubah cukup tinggi sehingga pilihan tidak akan menggigit Anda kembali untuk sementara waktu.
sumber
Bahasa pemrograman dirancang untuk dieksekusi oleh komputer. Semua blok bangunan penting komputer - CPU, RAM, cache, disk - bisa berubah. Ketika mereka tidak (BIOS), mereka benar-benar tidak dapat berubah dan Anda tidak dapat membuat objek baru juga.
Oleh karena itu, bahasa pemrograman apa pun yang dibangun di atas objek yang tidak dapat diubah akan mengalami kesenjangan representasi dalam implementasinya. Dan untuk bahasa awal seperti C, itu adalah batu sandungan besar.
sumber
Tanpa objek yang bisa berubah, Anda tidak memiliki status. Harus diakui, ini adalah hal yang baik jika Anda dapat mengelolanya dan jika ada kemungkinan suatu objek dapat dirujuk dari lebih dari satu utas. Tetapi program ini akan agak membosankan. Banyak perangkat lunak, terutama server web, menghindari mengambil tanggung jawab untuk objek yang dapat berubah dengan mendorong mutabilitas pada basis data, sistem operasi, pustaka sistem, dll. Sebagai masalah praktis, ini membebaskan programmer dari masalah kemampuan berubah dan membuat web (dan lainnya) pengembangan terjangkau. Tetapi mutabilitas masih ada.
Secara umum, Anda memiliki tiga jenis kelas: kelas normal, tidak aman, yang harus dijaga dan dilindungi dengan hati-hati; kelas abadi, yang dapat digunakan secara bebas; dan kelas yang bisa diubah, thread-safe yang dapat digunakan secara bebas tetapi harus ditulis dengan sangat hati-hati. Tipe pertama adalah tipe yang merepotkan, dengan tipe terburuk adalah tipe yang dianggap tipe ketiga. Tentu saja, tipe pertama adalah yang mudah untuk ditulis.
Saya biasanya berakhir dengan banyak kelas yang normal dan bisa berubah yang harus saya perhatikan dengan sangat hati-hati. Dalam situasi multi-utas, sinkronisasi yang diperlukan memperlambat segalanya bahkan ketika saya dapat menghindari pelukan mematikan. Jadi saya biasanya membuat salinan yang tidak dapat diubah dari kelas yang bisa berubah dan memberikannya kepada siapa pun yang dapat menggunakannya. Salinan abadi yang baru diperlukan setiap kali orignal bermutasi, jadi saya membayangkan kadang-kadang saya mungkin memiliki seratus salinan asli di luar sana. Saya sangat bergantung pada Pengumpulan Sampah.
Singkatnya, objek yang tidak dapat diubah, objek yang dapat ditransmisikan baik-baik saja jika Anda tidak menggunakan banyak utas. (Tapi multithreading inflitrating di mana-mana - hati-hati!) Mereka dapat digunakan dengan aman jika Anda membatasi mereka ke variabel lokal atau menyinkronkannya dengan ketat. Jika Anda dapat menghindarinya dengan menggunakan kode orang lain yang terbukti (DB, panggilan sistem, dll.) Melakukannya. Jika Anda bisa menggunakan kelas yang tidak dapat diubah, lakukanlah. Dan saya pikir , secara umum , orang-orang entah tidak menyadari masalah multithreading atau (masuk akal) takut pada mereka dan menggunakan semua jenis trik untuk menghindari multithreading (atau lebih tepatnya, mendorong tanggung jawab untuk itu di tempat lain).
Sebagai seorang PS, saya merasakan bahwa Java getter dan setters sudah lepas kendali. Lihat ini .
sumber
Banyak orang memiliki jawaban yang baik jadi saya ingin menunjukkan sesuatu yang Anda sentuh yang sangat jeli dan sangat benar dan belum disebutkan di tempat lain di sini.
Secara otomatis membuat setter dan getter adalah ide yang mengerikan, mengerikan, namun ini adalah cara pertama orang yang berpikir prosedural mencoba memaksa OO ke dalam pola pikir mereka. Setter dan getter, bersama dengan properti seharusnya hanya dibuat ketika Anda menemukan Anda membutuhkannya dan tidak setiap orang secara default
Bahkan walaupun Anda membutuhkan getter secara teratur, satu-satunya cara setter atau properti yang dapat ditulis harus ada dalam kode Anda adalah melalui pola pembangun di mana mereka dikunci setelah objek telah sepenuhnya instantiated.
Banyak kelas yang bisa berubah setelah penciptaan yang baik-baik saja, itu tidak seharusnya memiliki sifat-sifatnya dimanipulasi secara langsung - melainkan harus diminta untuk memanipulasi sifat-sifatnya melalui pemanggilan metode dengan logika bisnis aktual di dalamnya (Ya, seorang setter hampir sama hal yang secara langsung memanipulasi properti)
Sekarang ini tidak benar-benar berlaku untuk kode / bahasa gaya "Scripting" baik tetapi untuk kode yang Anda buat untuk orang lain dan mengharapkan orang lain untuk membaca berulang kali selama bertahun-tahun. Saya harus mulai membuat perbedaan itu belakangan ini karena saya sangat menikmati bermain-main dengan Groovy dan ada perbedaan besar dalam target.
sumber
Objek yang dapat diubah digunakan ketika Anda harus menetapkan nilai kelipatan setelah instantiasi objek.
Anda seharusnya tidak memiliki konstruktor dengan, katakanlah, enam parameter. Alih-alih Anda memodifikasi objek dengan metode penyetel.
Contoh dari ini adalah objek Laporan, dengan setter untuk font, orientasi dll.
Singkatnya: bisa berubah berguna ketika Anda memiliki banyak negara untuk mengatur ke objek dan itu tidak praktis untuk memiliki tanda tangan konstruktor yang sangat panjang.
EDIT: Pola pembangun dapat digunakan membangun seluruh keadaan objek.
sumber
new ReportBuilder().font("Arial").orientation("landscape").build()
withFont
mengembalikan aReport
.Saya pikir menggunakan objek yang bisa berubah berasal dari pemikiran imperatif: Anda menghitung hasilnya dengan mengubah konten variabel yang dapat berubah langkah demi langkah (perhitungan dengan efek samping).
Jika Anda berpikir secara fungsional, Anda ingin memiliki status yang tidak dapat diubah dan mewakili status berikutnya dari suatu sistem dengan menerapkan fungsi-fungsi dan menciptakan nilai-nilai baru dari yang lama.
Pendekatan fungsional bisa lebih bersih dan lebih kuat, tetapi bisa sangat tidak efisien karena penyalinan, sehingga Anda ingin kembali ke struktur data bersama yang Anda modifikasi secara bertahap.
Trade-off yang menurut saya paling masuk akal adalah: Mulailah dengan objek yang tidak dapat diubah dan kemudian beralih ke objek yang dapat berubah jika implementasi Anda tidak cukup cepat. Dari sudut pandang ini, menggunakan objek yang bisa berubah secara sistematis dari awal dapat dianggap semacam optimasi prematur : Anda memilih implementasi yang lebih efisien (tetapi juga lebih sulit untuk dipahami dan debug) dari awal.
Jadi, mengapa banyak programmer menggunakan objek yang bisa berubah? IMHO karena dua alasan:
sumber
Saya tahu Anda bertanya tentang Java, tapi saya menggunakan bisa berubah vs tidak berubah sepanjang waktu di tujuan-c. Ada larik NSArray yang tidak berubah, dan larik NSMutableArray yang bisa berubah. Ini adalah dua kelas berbeda yang ditulis secara khusus dengan cara yang dioptimalkan untuk menangani penggunaan yang tepat. Jika saya perlu membuat array dan tidak pernah mengubah isinya, saya akan menggunakan NSArray, yang merupakan objek yang lebih kecil dan jauh lebih cepat dalam fungsinya, dibandingkan dengan array yang bisa berubah.
Jadi jika Anda membuat objek Person yang tidak dapat diubah maka Anda hanya perlu konstruktor dan getter, sehingga objek tersebut akan lebih kecil dan menggunakan lebih sedikit memori, yang pada gilirannya akan membuat program Anda sebenarnya lebih cepat. Jika Anda perlu mengubah objek setelah pembuatan, maka objek Person yang dapat berubah akan lebih baik sehingga dapat mengubah nilai alih-alih membuat objek baru.
Jadi: tergantung pada apa yang Anda rencanakan untuk dilakukan dengan objek, memilih bisa berubah vs tidak berubah dapat membuat perbedaan besar, ketika datang ke kinerja.
sumber
Tambahan untuk banyak alasan lain yang diberikan di sini, masalahnya adalah bahwa bahasa utama tidak mendukung immutabilitas dengan baik. Paling tidak, Anda dihukum karena tidak dapat diubah karena Anda harus menambahkan kata kunci tambahan seperti const atau final, dan harus menggunakan konstruktor yang tidak terbaca dengan banyak, banyak argumen atau kode pola pembangun yang panjang.
Itu jauh lebih mudah dalam bahasa-bahasa yang dibuat dengan ketidakberimbangan dalam pikiran. Pertimbangkan potongan Scala ini untuk mendefinisikan Orang kelas, opsional dengan argumen bernama, dan membuat salinan dengan atribut yang diubah:
Jadi, jika Anda ingin pengembang mengadopsi imutabilitas, ini adalah salah satu alasan mengapa Anda mungkin mempertimbangkan untuk beralih ke bahasa pemrograman yang lebih modern.
sumber
Tidak Berubah berarti Anda tidak dapat mengubah nilai, dan bisa berubah berarti Anda dapat mengubah nilai jika Anda berpikir dalam hal primitif, dan objek. Objek berbeda dari primitif di Jawa dalam bentuk objek. Primitif dibangun dalam tipe seperti int, boolean, dan void.
Banyak orang berpikir bahwa variabel primitif dan objek yang memiliki pengubah akhir di depannya tidak dapat diubah, namun, ini tidak sepenuhnya benar. Jadi akhir hampir tidak berarti tidak berubah untuk variabel. Lihat tautan ini untuk contoh kode:
sumber
Saya pikir alasan yang bagus adalah untuk memodelkan "benda" nyata "yang bisa berubah", seperti jendela antarmuka. Samar-samar saya ingat pernah membaca bahwa OOP ditemukan ketika seseorang mencoba menulis perangkat lunak untuk mengendalikan beberapa operasi pelabuhan kargo.
sumber
Java, dalam banyak kasus mandat objek yang dapat diubah, misalnya ketika Anda ingin menghitung atau mengembalikan sesuatu di pengunjung atau runnable, Anda memerlukan variabel akhir, bahkan tanpa multithreading.
sumber
final
sebenarnya sekitar 1/4 langkah menuju keabadian. Tidak melihat mengapa Anda menyebutkannya.final
. Membesarkannya dalam konteks ini memunculkan penggabungan yang sangat anehfinal
dengan "bisa berubah", ketika intinyafinal
adalah untuk mencegah jenis mutasi tertentu. (BTW, bukan downvote saya.)