Berasal dari latar belakang OOP (Jawa), saya belajar Scala sendiri. Sementara saya dapat dengan mudah melihat keuntungan dari menggunakan objek yang tidak dapat diubah secara individual, saya mengalami kesulitan melihat bagaimana seseorang dapat merancang seluruh aplikasi seperti itu. Saya akan memberi contoh:
Katakanlah saya memiliki objek yang mewakili "bahan" dan sifat-sifatnya (saya merancang permainan, jadi saya benar-benar memiliki masalah itu), seperti air dan es. Saya akan memiliki "manajer" yang memiliki semua contoh materi seperti itu. Satu properti akan menjadi titik beku dan leleh, dan bahan itu membeku atau meleleh.
[EDIT] Semua instance materi adalah "singleton", semacam Java Enum.
Saya ingin "air" untuk mengatakan itu membeku menjadi "es" pada 0C, dan "es" untuk mengatakan itu mencair menjadi "air" pada 1C. Tetapi jika air dan es tidak dapat diubah, mereka tidak dapat mendapatkan referensi satu sama lain sebagai parameter konstruktor, karena salah satunya harus dibuat terlebih dahulu, dan bahwa seseorang tidak bisa mendapatkan referensi ke yang lain yang belum ada sebagai parameter konstruktor. Saya bisa menyelesaikan ini dengan memberi mereka berdua referensi ke manajer sehingga mereka dapat meminta itu untuk menemukan contoh material lain yang mereka butuhkan setiap kali mereka diminta untuk pembekuan / sifat lelehnya, tetapi kemudian saya mendapatkan masalah yang sama antara manajer dan bahan-bahan, yang mereka butuhkan referensi satu sama lain, tetapi hanya dapat disediakan di konstruktor untuk salah satu dari mereka, sehingga manajer atau bahan tidak dapat berubah.
Apakah tidak ada jalan keluar untuk masalah ini, atau apakah saya perlu menggunakan teknik pemrograman "fungsional", atau beberapa pola lain untuk menyelesaikannya?
sumber
h2o
bahanJawaban:
Solusinya adalah sedikit curang. Secara khusus:
Buat A, tetapi biarkan referensi ke B tidak diinisialisasi (karena B belum ada).
Buat B, dan arahkan ke A.
Perbarui A ke titik B. Jangan memperbarui A atau B setelah ini.
Ini dapat dilakukan secara eksplisit (contoh dalam C ++):
atau secara implisit (contoh dalam Haskell):
Contoh Haskell menggunakan evaluasi malas untuk mencapai ilusi nilai-nilai abadi yang saling bergantung. Nilai dimulai sebagai:
a
danb
keduanya merupakan bentuk normal kepala yang valid secara independen. Setiap kontra dapat dibangun tanpa memerlukan nilai akhir dari variabel lain. Ketika thunk dievaluasi, maka akan menunjuk ke titik data yang samab
.Jadi, jika Anda ingin dua nilai yang tidak dapat diubah untuk menunjuk satu sama lain, Anda harus memperbarui yang pertama setelah membangun yang kedua, atau menggunakan mekanisme tingkat yang lebih tinggi untuk melakukan hal yang sama.
Dalam contoh khusus Anda, saya dapat mengungkapkannya di Haskell sebagai:
Namun, saya melangkahi masalah ini. Saya akan membayangkan itu dalam pendekatan berorientasi objek, di mana sebuah
setTemperature
metode melekat pada hasil masing-masingMaterial
konstruktor, Anda harus memiliki titik konstruktor satu sama lain. Jika konstruktor diperlakukan sebagai nilai yang tidak dapat diubah, Anda dapat menggunakan pendekatan yang diuraikan di atas.sumber
Dalam contoh Anda, Anda menerapkan transformasi ke objek jadi saya akan menggunakan sesuatu seperti
ApplyTransform()
metode yang mengembalikanBlockBase
daripada mencoba mengubah objek saat ini.Misalnya, untuk mengubah IceBlock ke WaterBlock dengan menerapkan panas, saya akan memanggil sesuatu seperti
dan
IceBlock.ApplyTemperature()
metodenya akan terlihat seperti ini:sumber
BlockList.WaterBlock
daripada membuat blok baru?BlockList
hanyastatic
kelas yang bertanggung jawab untuk instance tunggal dari setiap blok, jadi Anda tidak perlu membuat instance dariBlockList
(Saya sudah terbiasa dengan C #)Cara lain untuk memutus siklus adalah dengan memisahkan masalah materi dan transmutasi, dalam beberapa bahasa yang dibuat-buat:
sumber
Jika Anda akan menggunakan bahasa fungsional, dan Anda ingin menyadari manfaat dari keabadian, maka Anda harus mendekati masalah dengan itu dalam pikiran. Anda sedang mencoba untuk menentukan jenis objek "es" atau "air" yang dapat mendukung berbagai suhu - untuk mendukung kekekalan, Anda kemudian perlu membuat objek baru setiap kali perubahan suhu, yang boros. Jadi cobalah membuat konsep tipe blok dan suhu lebih mandiri. Saya tidak tahu Scala (ada di daftar to-learn saya :-)), tetapi meminjam dari Joey Adams Answer di Haskell , saya menyarankan sesuatu seperti:
atau mungkin:
(Catatan: Saya belum mencoba menjalankan ini, dan Haskell saya agak berkarat.) Sekarang, logika transisi dipisahkan dari jenis material, sehingga tidak membuang banyak memori, dan (menurut saya) cukup sedikit lebih berorientasi fungsional.
sumber