Bagaimana jika global masuk akal?

10

Saya punya nilai yang dibutuhkan banyak objek. Misalnya, aplikasi keuangan dengan investasi berbeda sebagai objek, dan sebagian besar membutuhkan tingkat bunga saat ini.

Saya berharap merangkum "lingkungan keuangan" saya sebagai objek, dengan tingkat bunga sebagai properti. Tetapi, objek saudara kandung yang membutuhkan nilai itu tidak dapat mencapai itu.

Jadi, bagaimana cara saya membagikan nilai di antara banyak objek tanpa menyandingkan desain saya secara berlebihan? Jelas saya memikirkan hal yang salah ini.

Greg
sumber
2
Apakah suku bunga tetap selama jangka waktu perhitungan Anda atau apakah Anda melakukan sesuatu seperti simulasi yang dapat bervariasi antar waktu?
James
Ini lebih seperti simulasi - itu dapat berubah selama menjalankan.
Greg
Dalam hal itu apakah setiap investasi benar-benar perlu untuk menyelamatkan suku bunga atau dapatkah ia menerimanya melalui parameter ke updatefungsi yang disebut di setiap catatan waktu? Bisakah Anda memposting di pseudocode bagaimana simulasi Anda beroperasi?
James
3
Anda adalah salah satu jalur yang benar, a Singletonadalah global dengan gula sintaksis OO di atasnya dan merupakan solusi mengerikan yang dengan ketat memasangkan kode Anda dalam beberapa cara terburuk yang mungkin. Baca artikel ini berulang-ulang sampai Anda memahaminya!
Suku bunga seperti Time Series yang merupakan fungsi yang mengambil DateTimeinput dan mengembalikan angka sebagai output.
rwong

Jawaban:

14

Saya punya nilai yang dibutuhkan banyak objek.

Ini adalah bau desain. Jarang bahwa banyak objek perlu tahu tentang sesuatu. Yang mengatakan, suku bunga saat ini adalah contoh yang cukup baik dari keadaan luar biasa. Satu hal yang perlu dikhawatirkan adalah jarang ada suku bunga. Instrumen keuangan yang berbeda menggunakan kurs yang berbeda pula. Paling tidak, lokal yang berbeda menggunakan tarif 'standar' yang berbeda. Selanjutnya, untuk membantu dalam pengujian dan pelaporan, Anda biasanya ingin memberikan nilai karena Anda tidak ingin menggunakan nilai saat ini di sana. Anda ingin menggunakan tingkat 'bagaimana jika' atau 'pada tanggal pelaporan'.

Jadi, bagaimana cara saya membagikan nilai di antara banyak objek tanpa menyandingkan desain saya secara berlebihan?

Dengan membagikannya, tidak memiliki semuanya merujuk pada satu contoh. Melewati hal yang sama di sekitar masih kopling ke tingkat, tetapi tidak over kopling karena sesuatu seperti suku bunga saat ini diperlukan sebagai input ke berbagai perhitungan.

Telastyn
sumber
17
Masalah dengan keadaan luar biasa adalah bahwa dalam perangkat lunak dunia nyata mereka tidak begitu luar biasa.
mattnz
Saya pikir ini adalah kesalahpahaman yang serius. Algoritma kami ada dalam konteks yang berbeda secara bersamaan. Yang pertama adalah konteks global. Lalu konteks "ini" untuk bahasa berorientasi objek. Konteks sesi dalam layanan web, konteks transaksi dalam lingkungan DB, jendela utama untuk gui, ... dan ada informasi yang termasuk dalam konteks ini. Mereka harus "berkeliaran" dan tersedia, set yang sama (objek) untuk siapa pun dalam konteks yang sama. Ini tidak apa-apa Masalahnya adalah menyelesaikan ini untuk setiap objek, bukan dengan membuat layanan konteks atau menggunakan kerangka kerja, seperti Spring in Java.
Lorand Kedves
3
Tidak ada yang luar biasa tentang tingkat bunga saat ini. Ada banyak contoh item dunia nyata yang memiliki satu nilai, - Batas kecepatan jalan terbuka, tingkat alkohol dalam darah yang dapat diterima, tarif pajak GST (atau PPN) untuk beberapa nama. Itulah perbedaan antara Sains dan Teknik - Insinyur memecahkan masalah dunia nyata saat ini, Para ilmuwan bermimpi suatu hari dunia nyata akan masuk ke dalam kotak kesempurnaan yang bagus dan menyelesaikan masalah tersebut.
mattnz
1
Saya memilih ini sebagai jawaban karena sederhana dan tidak bergantung pada pengalaman OOP selama satu dekade. BANYAK terima kasih kepada semua responden. Saya punya satu hari penuh membaca berkat banyak referensi tetapi masih sedikit bingung. Untuk pertanyaan sederhana seperti itu, saya terkejut dengan variasi, dan emosi di balik, tanggapan. Saya tetap yakin bahwa kadang-kadang ada sumber utama data global namun beragam yang paling baik dilayani oleh Singleton. Saya tidak akan berpikir seseorang harus melewati pointer naik turun hierarki objek hanya untuk menghindari Singleton. Terima kasih sekali lagi semuanya.
Greg
@ mattnz, masalahnya adalah bahwa setiap contoh Anda adalah variabel dalam kasus di mana Anda mendistribusikan program Anda ke beberapa basis pengguna yang dapat menjangkau perusahaan, negara bagian, atau negara. Semua itu juga bisa variabel dari waktu ke waktu.
Dan Lyons
10

Dalam contoh khusus ini saya akan menggunakan Pola Singleton . FinancialEnvironment akan menjadi objek yang diketahui semua perpustakaan kelas lainnya, tetapi akan dipakai oleh Singleton. Idealnya Anda kemudian akan mengirim objek instantiated itu ke berbagai pustaka kelas.

Sebagai contoh:

  • Lapisan Layanan (perpustakaan kelas) - Instantiate objek FinancialEnvironment melalui singleton
  • Business Logic Layer (class library) - Menerima objek FinancialEnvironment dari lapisan layanan
  • Lapisan Akses Data (perpustakaan kelas) - Menerima objek FinancialEnvironment dari lapisan layanan (atau tergantung pada arsitektur Anda, Lapisan Logika Bisnis). Atau mungkin Singleton memanggil Layer Akses Data untuk mendapatkan informasi, seperti suku bunga, dari repositori (layanan basis data / web / layanan WCF) apa pun.
  • Entitas (atau DTO jika Anda ingin menyebutnya demikian) pustaka kelas - Di mana objek FinancialEnvironment hidup. Semua pustaka kelas lainnya memiliki referensi ke pustaka kelas Entitas.

Kelas-kelas lain hanya diikat bersama melalui perpustakaan kelas Entitas, mereka menerima objek FinancialEnvironment instantiated. Mereka tidak peduli bagaimana itu dibuat, hanya lapisan layanannya, yang mereka inginkan hanyalah informasinya. Singleton juga bisa cukup pintar untuk menyimpan beberapa objek FinancialEnvironment, tergantung pada aturan untuk lokal seperti yang ditunjukkan @Telastyn.

Sebagai catatan, saya bukan penggemar berat Pola Singleton, saya menganggapnya sebagai bau kode, karena dapat disalahgunakan dengan sangat mudah. Tetapi dalam beberapa kasus Anda membutuhkannya.

Memperbarui:

Jika Anda benar-benar, secara positif harus memiliki variabel global, maka menerapkan Pola Singleton seperti dijelaskan di atas akan berhasil. Namun, saya bukan penggemar berat ini, dan berdasarkan komentar dari posting asli saya, beberapa orang lain juga tidak. Sebagai sesuatu yang tidak stabil seperti InterestRate, Singleton mungkin bukan solusi terbaik. Lajang bekerja paling baik ketika informasi tidak berubah. Misalnya, saya menggunakan Singleton di salah satu aplikasi saya untuk membuat instance penghitung kinerja. Karena jika mereka berubah maka Anda harus memiliki logika untuk menangani data yang diperbarui.

Jika saya seorang taruhan, saya berani bertaruh tingkat bunga disimpan di suatu tempat di dalam basis data, atau diambil melalui layanan web. Dalam hal itu Repositori (lapisan akses data) akan direkomendasikan untuk mengambil informasi itu. Untuk menghindari perjalanan yang tidak perlu ke database (saya tidak yakin seberapa sering suku bunga berubah, atau informasi lain di kelas FinancialInformation), caching dapat digunakan. Di dunia C # perpustakaan Caching Aplikasi Microsoft blok bekerja dengan sangat baik.

Satu-satunya hal yang akan berubah dari contoh di atas, adalah berbagai kelas di lapisan layanan yang memerlukan Informasi Keuangan akan mengambil dari Data Access Layer alih-alih Singleton yang instantiating objek.

bwalk2895
sumber
8
Ugh. Menjadikan global sebagai singleton tidak membuatnya kurang bau. Jika Anda membatasi diri Anda, itu jauh lebih baik.
Telastyn
3
@ Davidvidow tidak masalah jika mereka tidak rumit untuk diterapkan; mereka lebih buruk desain Anda daripada global. Mereka bersifat global dan mereka memberlakukan batasan (yang tidak dibutuhkan) yang hanya Anda miliki.
Telastyn
4
Saya akan memposting komentar sarkastik sayin "jadikan singleton dan itu akan berubah dari praktik buruk menjadi praktik terbaik", tetapi kemudian saya melihat itu sudah merupakan jawaban yang diterima dan dipilih. Sangat bagus!
Kevin
4
Singletonadalah global dengan gula sintaksis OO dan kruk bagi yang malas dan berpikiran lemah. Singleton/globaladalah cara terburuk yang mutlak untuk memasangkan kode Anda dengan ketat ke sesuatu yang nantinya akan menjadi kanker ketika Anda menyadari betapa itu ide yang sangat buruk dan mengapa semua orang mengatakan itu!
4
@ Telastyn: Ini adalah kenyataan yang sangat disayangkan bahwa desain yang paling sempurna begitu mereka meninggalkan dunia desain perangkat lunak teoritis yang tertata dengan sempurna dan bergabung dengan dunia nyata, dapatkan fubar'd.
mattnz
4

File Konfigurasi?

Jika Anda memiliki nilai yang digunakan "secara global", harap masukkan dalam file konfigurasi. Kemudian setiap sistem dan subsistem dapat merujuk ini dan menarik kunci yang diperlukan, membuatnya hanya baca.

Malam gelap
sumber
Jadi, Anda akan meminta pengguna memperbarui file konfigurasi setiap kali suku bunga berubah?
Caleb
2
Kenapa tidak? tergantung pada "variabel" tentu saja hal-hal yang sering berubah harus ditempatkan di dalam datastore terpusat.
Darknight
1

Saya berbicara dari pengalaman seseorang yang memiliki sekitar satu bulan pemeliharaan pada proyek berukuran baik (~ 50k LOC) yang baru saja kami rilis.

Saya dapat memberitahu Anda bahwa Anda mungkin tidak benar-benar menginginkan objek global. Memperkenalkan semacam itu memberikan banyak peluang untuk penyalahgunaan daripada membantu.

Saran awal saya adalah jika Anda memiliki beberapa kelas berbeda yang membutuhkan tingkat bunga saat ini maka Anda mungkin ingin mereka menerapkan IInterestRateConsumeratau sesuatu. Di dalam antarmuka itu Anda akan memiliki SetCurrentInterestRate(double rate)(atau apa pun yang masuk akal), atau mungkin hanya sebuah properti.

Melewati suku bunga di sekitar sebenarnya bukan penggandengan - Jika kelas Anda membutuhkan suku bunga, itu bagian dari API-nya. Ini hanya berpasangan jika salah satu kelas Anda mulai mengkhawatirkan dengan tepat bagaimana kelas lain menggunakan tingkat bunga itu.

Wayne Werner
sumber
Melewati suku bunga sekitar adalah kopling, itu bukan kopling yang buruk .
vaughandroid
1

Martin Fowler memiliki artikel yang membahas secara singkat tentang bagaimana cara memperbaiki global statis menjadi sesuatu yang lebih fleksibel. Pada dasarnya Anda membuatnya menjadi singleton kemudian memodifikasi singleton sehingga mendukung overriding kelas instance dengan subclass (dan jika perlu pindahkan logika yang membuat instance ke kelas terpisah yang dapat sub-class, yang akan Anda lakukan jika membuat instance kelas-super maka menggantinya nanti adalah masalah).

Tentu saja, Anda harus mempertimbangkan masalah dengan lajang (bahkan lajang yang dapat diganti) vs rasa sakit karena melewatkan benda yang sama di mana-mana.

Sejauh objek "lingkungan keuangan" - lebih mudah untuk memprogram pada pass pertama, tetapi ketika Anda selesai Anda telah menambahkan beberapa dependensi tambahan. Kelas yang hanya membutuhkan tingkat bunga sekarang hanya berfungsi ketika melewati objek lingkungan keuangan, yang akan membuat mereka sulit untuk digunakan kembali ketika Anda tidak memiliki objek lingkungan keuangan berbohong. Jadi saya akan mencegah melewatinya secara luas.

psr
sumber
0

Mengapa tidak memasukkan data suku bunga ke cache pusat?

Anda dapat menggunakan salah satu dari beberapa pustaka cache, yang mana yang paling sesuai dengan kebutuhan Anda, sesuatu seperti memcached menyelesaikan semua masalah manajemen mata uang dan kode Anda dan akan memungkinkan aplikasi Anda untuk menskala ke beberapa proses.

Atau pergilah seluruh babi dan simpanlah dalam basis data, yang akan memungkinkan Anda untuk mengukur ke beberapa server.

James Anderson
sumber
0

Dalam situasi seperti itu saya telah berhasil memperkenalkan (menggunakan kembali) istilah "konteks" dengan terkadang beberapa lapisan.

Ini berarti singleton, dengan demikian menyimpan objek "global", dari mana objek semacam ini dapat diminta. Kode yang memerlukannya, sertakan tajuk toko, dan gunakan fungsi global untuk mendapatkan instance objek mereka (seperti sekarang, penyedia suku bunga).

Toko dapat berupa:

  • diketik dengan ketat: Anda memasukkan header untuk semua jenis yang dilayani dan sehingga Anda dapat membuat pengakses yang diketik, seperti InterestRate getCurrentInterestRate ();
  • atau generik: Objek getObject (enum obType); dan hanya memperpanjang obType enum dengan jenis baru (obtypeCurrentInterestRate).

Semakin besar sistem, semakin dapat digunakan solusi yang terakhir, untuk risiko yang cukup kecil menggunakan enum yang salah. Di sisi lain, dengan bahasa yang memungkinkan deklarasi tipe forward, saya pikir Anda dapat menggunakan pengetik yang diketik tanpa menyertakan semua header di toko.

Satu catatan lagi: Anda mungkin memiliki beberapa instance dari jenis objek yang sama untuk kegunaan yang berbeda, seperti nilai Bahasa yang terkadang berbeda untuk GUI dan untuk cetakan, log tingkat sesi dan global, dll, sehingga nama enum / accessor TIDAK boleh mencerminkan jenis aktual , tetapi peran instance yang diminta (CurrentInterestRate).

Dalam implementasi toko, Anda harus mengelola level konteks dan koleksi instance konteks. Contoh sederhana adalah layanan web, di mana Anda memiliki konteks global (satu contoh untuk semua permintaan untuk objek itu - bermasalah ketika memiliki server server), dan konteks untuk setiap sesi web. Anda juga dapat memiliki konteks untuk setiap pengguna, yang mungkin memiliki banyak, sesi paralel, dll. Dengan beberapa server Anda harus menggunakan semacam cache terdistribusi untuk hal-hal seperti itu.

Ketika permintaan masuk, Anda memutuskan tingkat konteks objek yang diminta, dapatkan konteks untuk panggilan itu. Jika objek ada di sana, Anda mengirimnya kembali; jika tidak, Anda membuat dan menyimpannya di tingkat konteks itu, dan mengembalikannya. Tentu saja, sinkronkan bagian pembuatan (dan publikasikan ke cache yang didistribusikan). Pembuatannya bisa seperti plugin yang dapat dikonfigurasi, paling baik dengan bahasa yang memungkinkan pembuatan instance objek dengan nama kelasnya (Java, Objective C, ...), tetapi Anda bisa melakukannya di C juga dengan pustaka pluggable yang memiliki fungsi pabrik.

Catatan: penelepon TIDAK boleh tahu terlalu banyak tentang konteksnya sendiri, dan tingkat konteks objek yang diminta. Alasan: 1: mudah membuat kesalahan (atau "trik pintar") dengan memainkan parameter ini; 2: tingkat konteks yang diminta dapat berubah nanti. Saya sebagian besar menghubungkan informasi konteks ke utas, sehingga toko objek memiliki informasi tanpa parameter tambahan dari permintaan.

Di sisi lain, permintaan dapat berisi petunjuk untuk contoh: seperti mendapatkan suku bunga untuk tanggal tertentu. Itu haruslah akses "global" yang sama, tetapi beberapa kejadian tergantung pada tanggal (dan mengarahkan nilai tanggal yang berbeda ke contoh yang sama di antara perubahan tarif), sehingga disarankan untuk menambahkan objek "petunjuk" ke permintaan, digunakan oleh pabrik contoh dan bukan toko; dan keyForHint ke pabrik, digunakan oleh toko. Anda dapat menambahkan fungsi-fungsi ini nanti, saya baru saja menyebutkan.

Untuk kasus Anda, ini adalah jenis pembunuhan berlebihan (hanya satu objek yang dilayani di tingkat global), tetapi untuk kode tambahan yang cukup kecil dan sederhana sekarang, Anda mendapatkan mekanisme untuk persyaratan lebih lanjut, mungkin lebih kompleks.

Berita bagus lainnya: jika Anda berada di Jawa, Anda mendapatkan layanan ini dari Spring tanpa berpikir terlalu banyak, saya hanya ingin menjelaskannya secara terperinci.

Lorand Kedves
sumber
0

Alasan untuk TIDAK menggunakan global (atau singleton) adalah bahwa meskipun Anda awalnya berharap hanya memiliki satu nilai, sering kali berguna untuk dapat menggunakan kode yang sama beberapa kali dalam program yang sama, misalnya:

  • untuk menghitung apa yang AKAN terjadi jika suku bunga berbeda
  • untuk memiliki beberapa komponen tergantung pada suku bunga AS dan beberapa komponen tergantung pada suku bunga Inggris

Saya akan menjadikan suku bunga sebagai anggota kelas "instrumen keuangan", dan menerima bahwa Anda harus meneruskannya ke kelas anggota mana pun (baik per-perhitungan, atau memberi mereka penunjuk / pengait untuk konstruksi).

Jack V.
sumber
0

Hal-hal harus diteruskan dalam pesan, bukan dibaca dari benda global.

Tulains Córdova
sumber