Ya küreseller mantıklıysa?


10

Birçok nesnenin ihtiyacı olan bir değere sahibim. Örneğin, nesne olarak farklı yatırımlara sahip bir finansal uygulama ve bunların çoğu cari faiz oranına ihtiyaç duymaktadır.

"Finansal ortamımı" bir nesne olarak, faiz oranı bir mülk olarak kapsama almayı umuyordum. Ancak, bu değere ihtiyaç duyan kardeş nesneler buna ulaşamaz.

Öyleyse tasarımımı fazla birleştirmeden değerleri birçok nesne arasında nasıl paylaşabilirim? Açıkçası bunu yanlış düşünüyorum.


2
Faiz oranı hesaplamalarınız süresince sabit mi, yoksa zaman döngüleri arasında değişebileceği bir simülasyon gibi bir şey mi yapıyorsunuz?
James

Daha çok bir simülasyon gibidir - koşu sırasında değişebilir.
Greg

Bu durumda, her yatırımın faiz oranını gerçekten kurtarması gerekir updatemi yoksa her bir zaman aralığında çağrılan bir fonksiyona bir parametre üzerinden alabilir mi? Simülasyonunuzun nasıl çalıştığını sözde kodla gönderebilir misiniz?
James

3
Doğru pistten birisiniz, a Singleton, OO sözdizimsel şekeri olan bir küresel ve kodunuzu mümkün olan en kötü yollardan sıkıca birleştiren korkunç bir çözümdür. Anlayana kadar bu makaleyi tekrar tekrar okuyun !

Faiz oranı, girdi olarak alan ve sayıyı çıktı olarak döndüren bir fonksiyon olan Zaman Serisi gibidir DateTime.
rwong

Yanıtlar:


14

Birçok nesnenin ihtiyaç duyduğu bir değere sahibim.

Bu bir tasarım kokusudur. Birçok nesnenin bir şey hakkında bilmesi gerekmesi nadirdir. Bununla birlikte, mevcut faiz oranı istisnai koşulların oldukça iyi bir örneğidir. Endişe gereken tek şey hakkında nadiren var olmasıdır faiz oranı. Farklı finansal araçlar farklı oranlar kullanır. En azından, farklı yerel ayarlar farklı 'standart' oranları kullanır. Ayrıca, test ve raporlamaya yardımcı olmak için, oradaki geçerli ücreti kullanmak istemediğiniz için genellikle bir ücret iletmek istersiniz . 'Rapor tarihi itibariyle' ne olursa 'veya' ne olursa olsun 'oranını kullanmak istersiniz.

Öyleyse tasarımımı fazla birleştirmeden değerleri birçok nesne arasında nasıl paylaşabilirim?

Onları paylaşarak, hepsinin tek bir örneğe başvurmamasını sağlamak. Aynı şeyin etrafından geçilmesi hala bir dereceye kadar eşleşmektedir, ancak çeşitli hesaplamalara girdi olarak cari faiz oranı gibi bir şeye ihtiyaç duyulduğundan, fazla kuplaj değildir .


17
İstisnai koşulların sorunu, gerçek dünya yazılımında bu kadar istisnai olmamalarıdır.
mattnz

Bunun ciddi bir yanlış anlama olduğunu düşünüyorum. Algoritmalarımız aynı anda farklı bağlamlarda bulunur. Birincisi küresel bağlam. Sonra nesne yönelimli diller için "bu" bağlam. Bir web hizmetinde oturum bağlamı, bir DB ortamında işlem bağlamı, bir GUI için ana pencere, ... ve bu bağlamlara ait bilgi parçaları vardır. Aynı bağlamdaki herkes için aynı küme (nesneler) "takılmalı" ve kullanılabilir olmalıdırlar. Tamamdır. Sorun, bunu bir bağlam hizmeti oluşturarak veya Java'da Spring gibi bir çerçeve kullanarak değil, her nesne için çözmektir.
Lorand Kedves

3
Cari faiz oranı ile ilgili istisnai bir şey yoktur. Bir değeri olan gerçek dünya maddesinin birçok örneği vardır, - Açık yol Hız sınırı, kabul edilebilir kan alkol seviyesi, GST (veya KDV) vergi oranı çok azdır. Bilim ve Mühendislik arasındaki fark budur - Mühendisler günümüzün gerçek dünya sorunlarını çözer, Bilim adamları gerçek dünyanın güzel mükemmellik kutularına sığacağı ve bu sorunları çözeceği günün hayalini kurar.
mattnz

1
Bunu cevap olarak seçtim çünkü basit ve grok için on yıllık bir OOP deneyimine güvenmiyor. Tüm katılımcılara çok teşekkürler. Birçok referans sayesinde tam bir gün okumuştum ama yine de biraz şaşkınım. Böyle basit bir soru için cevapların çeşitliliğine ve arkasındaki duygulara şaşırdım. Bazen en iyi şekilde bir Singleton tarafından sunulan merkezi fakat küresel bir veri kaynağı olduğuna ikna oldum. Ben sadece bir Singleton önlemek için bir nesne hiyerarşisi işaretçiler yukarı ve aşağı geçmek gerektiğini düşünmek olmaz. Herkese tekrar teşekkürler.
Greg

@mattnz, sorun, programınızı şirketlere, eyaletlere veya ülkelere yayılabilecek birden fazla kullanıcı tabanına dağıttığınız durumlarda, örneklerinizin her birinin değişken olmasıdır. Hepsi de zaman içinde değişken olabilir.
Dan Lyons

10

Bu örnekte Singleton Paternini kullanırım . FinancialEnvironment, diğer tüm sınıf kütüphanelerinin bildiği bir nesne olacaktır, ancak Singleton tarafından somutlaştırılacaktır. İdeal olarak, bu örneklenmiş nesneyi çeşitli sınıf kitaplıklarına gönderirsiniz.

Örneğin:

  • Hizmet Katmanı (sınıf kitaplığı) - FinancialEnvironment nesnesini tek birton üzerinden başlatır
  • Business Logic Layer (sınıf kütüphanesi) - FinancialEnvironment nesnesini hizmet katmanından kabul eder
  • Veri Erişim Katmanı (sınıf kitaplığı) - Hizmet katmanından (veya mimarınıza bağlı olarak İş Mantık Katmanı) FinancialEnvironment nesnesini kabul eder. Ya da Singleton, veri erişim katmanını, faiz oranı gibi bilgileri bir depodan (veritabanı / web hizmeti / WCF hizmeti) ne olursa olsun almaya çağırır.
  • Varlıklar (veya bunu çağırmak istiyorsanız DTO'lar) sınıf kitaplığı - FinancialEnvironment nesnesinin yaşadığı yer. Diğer tüm sınıf kütüphanelerinin, Entities sınıf kütüphanesine bir referansı vardır.

Diğer sınıflar yalnızca Varlıklar sınıf kitaplığıyla birbirine bağlanır, örneklenmiş bir FinancialEnvironment nesnesini kabul ederler. Nasıl yaratıldıklarıyla ilgilenmezler, sadece hizmet katmanı yapar, istedikleri tek şey bilgidir. Singleton, @Telastyn'in işaret ettiği gibi yerel kurallara bağlı olarak birkaç FinancialEnvironment nesnesini saklayacak kadar akıllı olabilir.

Bir yan notta, ben Singleton Desen büyük bir hayranı değilim, çok kolay kötüye kullanılabilir gibi, bir kod kokusu olduğunu düşünüyorum. Ancak bazı durumlarda buna ihtiyacınız vardır.

Güncelleme:

Kesinlikle, olumlu bir global değişken olması gerekiyorsa, o zaman yukarıda açıklanan Singleton Desenini uygulamak işe yarayacaktır. Ancak, bunun büyük bir hayranı değilim ve orijinal yazımın yorumlarına dayanarak, birkaç kişi de değil. Bir Faiz Oranı kadar geçici bir şey olarak, bir Singleton en iyi çözüm olmayabilir. Singletons en iyi şekilde bilgi değişmediğinde çalışır. Örneğin, performans sayaçlarını başlatmak için uygulamalarımdan birinde bir Singleton kullandım. Çünkü bunlar değişiyorsa, güncellenmekte olan verileri işlemek için mantığınız olmalıdır.

Bahis yapan bir adam olsaydım, faiz oranının bir veritabanında bir yerde saklandığını ya da bir web servisi aracılığıyla alındığını iddia ederdim. Bu durumda, bu bilgiyi almak için bir Depo (veri erişim katmanı) önerilir. Veritabanına gereksiz gezilerden kaçınmak için (faiz oranlarının veya FinancialInformation sınıfındaki diğer bilgilerin ne sıklıkta değiştiğinden emin değilim), önbellekleme kullanılabilir. C # dünyasında Microsoft'un Önbellek Uygulama Bloğu kütüphanesi çok iyi çalışıyor.

Yukarıdaki örnekten değişecek tek şey, hizmet katmanında FinancialInformation'a ihtiyaç duyan çeşitli sınıfların, nesneyi örnekleyen Singleton yerine Veri Erişim Katmanından alacağıdır.


8
Ugh. Küresel olanı bir single yapmak daha az koklamak anlamına gelmez. Kendinizi bu kadar kısıtlayan bir şey varsa.
Telastyn

3
@DavidCowden uygulanması karmaşık olmadıkları önemli değil; tasarımınızı küresellerden daha kötü biliyorlar. Onlar küresel konum ve onlar sadece bir tane var ki (gereksiz) kısıtlamasını zorlar.
Telastyn

4
"Bunu tekil yap ve kötü uygulamadan en iyi uygulamaya geçecek" diyerek alaycı bir yorum gönderecektim, ama sonra zaten kabul edilmiş ve oylanmış bir cevap olduğunu gördüm. Çok hoş!
Kevin

4
SingletonOO sözdizimsel şekeri ile küresel ve tembel ve zayıf fikirli bir koltuk değneği. kodunuzu, daha sonra ne kadar kötü bir fikir olduğunu ve herkesin neden böyle olduğunu söylediğinizde kanser olacak bir şeyle sıkıca birleştirmeninSingleton/global mutlak en kötü yoludur !

4
@Telastyn: Teorik yazılım tasarımının mükemmel düzenlenmiş dünyasını terk ettikten ve gerçek dünyaya katıldıktan sonra en mükemmel tasarımların şüphe duyduğu talihsiz bir gerçeklik.
mattnz

4

Yapılandırma Dosyaları?

"Global" olarak kullanılan değerleriniz varsa, lütfen bunları bir yapılandırma dosyasına yerleştirin. Daha sonra her sistem ve alt sistem buna başvurabilir ve gerekli anahtarları çekebilir, salt okunur hale getirebilir.


Yani faiz oranı her değiştiğinde kullanıcının bir yapılandırma dosyasını güncellemesini ister misiniz?
Caleb

2
Neden olmasın? "değişken" e bağlı olarak, sık sık değişen şeylerin MERKEZİLEŞTİRİLMİŞ bir veri deposuna yerleştirilmesi gerekir.
Darknight

1

Az önce piyasaya sürdüğümüz iyi büyüklükteki (~ 50k LOC) bir projede yaklaşık bir aylık bakım süresi olan birinden bahsediyorum.

Sana gerçekten küresel bir nesne istemediğini söyleyebilirim. Bu tür bir hamle tanışmak, istismar için yardımcı olduğundan çok daha fazla fırsat sağlar.

İlk önerim, şu andaki faiz oranına ihtiyaç duyan birkaç farklı sınıfınız varsa, muhtemelen bir IInterestRateConsumerya da bir şey uygulamalarını istemenizdir . Bu arayüzün içinde bir SetCurrentInterestRate(double rate)(ya da mantıklı ne varsa) ya da belki sadece bir mülk vardır.

Bir faiz oranını aktarmak aslında bir eşleştirme değildir - Sınıfınızın bir faiz oranına ihtiyacı varsa, bu API'sının bir parçasıdır. Sadece sınıflarınızdan biri diğer sınıfın bu faiz oranını tam olarak nasıl kullandığından endişelenmeye başlarsa birleşir.


Etrafında bir faiz oranı Geçme olan sadece değil, kavrama kötü kavrama.
vaughandroid

1

Martin Fowler, statik bir küreselliği daha esnek bir şeye nasıl yeniden aktaracağınızı kısaca anlatan bir makaleye sahiptir . Temelde bunu tekil bir hale getirirsiniz, sonra tektonu değiştirirsiniz, böylece örneğin sınıfını bir alt sınıfla geçersiz kılmayı destekler (ve gerekirse örneği oluşturan mantığı alt sınıflı ayrı bir sınıfa taşıyın; süper sınıf örneği oluşturuyorsanız, daha sonra değiştirmek bir sorundur).

Tabii ki, problemleri tekil nesnelerle (hatta ikame tekilleri bile) tartmak zorundasınız ve aynı nesneyi her yere geçirme acısına karşı.

"Finansal ortam" nesnesi kadar - ilk geçişte programlamak uygundur, ancak işiniz bittiğinde bazı ekstra bağımlılıklar eklediniz. Sadece bir faiz oranına ihtiyaç duyan sınıflar artık sadece bir finansal ortam nesnesinden geçtiğinde işlev görmektedir, bu da bir finansal ortam nesnesinin yalan söylemediğinizde yeniden kullanılmasını zorlaştıracaktır. Bu yüzden onu yaygın bir şekilde geçirmekten vazgeçireceğim.


0

Faiz oranı verilerini neden merkezi bir önbelleğe koymuyorsunuz?

Hangi önbellek kitaplığından birini kullanabilirsiniz, hangisi size en uygun olursa olsun, memcached gibi bir şey tüm eşzamanlılık ve kod yönetimi sorunlarını çözer ve uygulamanızın birden çok işleme ölçeklendirilmesini sağlar.

Veya tüm domuzları gidip birden fazla sunucuya ölçeklendirmenize izin verecek bir veritabanında saklayın.


0

Bu gibi durumlarda "bağlam" terimini bazen birden çok katmanla başarılı bir şekilde tanıttım (yeniden kullandım).

Bu, bu tür nesnelerin talep edilebileceği tek birton, dolayısıyla "global" nesne deposu anlamına gelir. Onları gerektiren kodlar, mağazanın üstbilgisini içerir ve nesne örneklerini almak için genel işlevleri kullanır (şimdi olduğu gibi, faiz oranı sağlayıcısı).

Mağaza şunlardan biri olabilir:

  • katı yazılır: sunulan tüm türlerin üstbilgilerini eklersiniz ve böylece InterestRate getCurrentInterestRate () gibi yazılı erişimciler oluşturabilirsiniz;
  • veya generic: Object getObject (enum obType); ve obType enum değerini yalnızca yeni türlerle (obtypeCurrentInterestRate) uzatın.

Sistem büyüdükçe, yanlış numaralandırma kullanma riski oldukça düşüktür. Öte yandan, ileri tip bildirimlere izin veren dillerle, mağazadaki tüm başlıkları içermeden yazılı erişimcileri kullanabileceğinizi düşünüyorum.

Bir not daha: farklı kullanımlar için bazen GUI ve çıktı, genel ve oturum düzeyi günlükleri için farklı Dil değeri gibi aynı nesne türünde birden çok örneğiniz olabilir, bu nedenle numaralandırma / erişimci adı gerçek türü DEĞİL , ancak istenen örneğin rolü (CurrentInterestRate).

Mağaza uygulamasında, bağlam düzeylerini ve bağlam örneği koleksiyonlarını yönetmeniz gerekir. Basit bir örnek, genel bağlama (o nesne için tüm istekler için bir örnek - bir sunucu grubuna sahipken sorunlu) sahip olduğunuz web hizmeti ve her web oturumu için bir bağlamdır. Ayrıca, birden çok paralel oturum vb. Olabilecek her kullanıcı için bağlamlarınız olabilir. Birden çok sunucuyla bu tür şeyler için bir tür dağıtılmış önbellek kullanmalısınız.

İstek geldiğinde, istenen nesnenin hangi bağlam düzeyinde olduğuna karar verirsiniz, çağrı için bu bağlamı alırsınız. Nesne oradaysa, onu geri gönderirsiniz; değilse, bu bağlam düzeyinde oluşturup saklar ve iade edersiniz. Tabii ki, oluşturma bölümünü senkronize edin (ve dağıtılmış önbellekte yayınlayın). Oluşturma, en iyi sınıf adlarına (Java, Objective C, ...) göre nesne örnekleri oluşturmaya izin veren dillerle yapılandırılabilir eklenti benzeri olabilir, ancak bunu C'de de fabrika işlevlerine sahip takılabilir kitaplıklarla yapabilirsiniz.

Yan not: arayan kendi bağlamları ve istenen nesnenin bağlam seviyesi hakkında çok fazla şey bilmemelidir. Sebepler: 1: bu parametrelerle oynayarak hata yapmak (veya "akıllı numaralar") kolaydır; 2: istenen içerik düzeyi daha sonra değişebilir. Çoğunlukla bağlam bilgisini iş parçacığına bağlarım, böylece nesne deposu, istekten fazladan parametre içermeyen bilgilere sahiptir.

Öte yandan, istek örnek için bir ipucu içerebilir: belirli bir tarih için faiz oranı almak gibi. Aynı "genel" erişim olmalıdır, ancak tarihe bağlı olarak birden çok örnek olmalıdır (ve ücret değişiklikleri arasında aynı örneğe farklı tarih değerleri yönlendirir). Bu nedenle, istek tarafından kullanılan isteğe bir "ipucu" nesnesi eklemeniz önerilir. mağaza değil fabrika; ve mağaza tarafından kullanılan fabrikaya bir anahtar. Bu işlevleri daha sonra ekleyebilirsiniz, az önce bahsetmiştim.

Sizin durumunuz için bu bir tür aşırıya kaçmadır (küresel düzeyde sadece bir nesne servis edilir), ancak şu anda oldukça küçük ve basit bir ekstra kod için, belki de daha karmaşık gereksinimler için bir mekanizma elde edersiniz.

Başka bir iyi haber: Java'daysanız, bu hizmeti çok fazla düşünmeden Spring'den alırsınız, sadece ayrıntılı olarak açıklamak istedim.


0

Global (veya singleton) kullanmamanın nedeni, başlangıçta yalnızca bir değere sahip olmayı beklemenize rağmen, aynı kodu aynı programda birden çok kez kullanabilmeniz genellikle şaşırtıcı derecede yararlıdır:

  • faiz oranı farklı olsaydı ne olacağını hesaplamak için
  • bazı bileşenlerin ABD faiz oranına ve bazı bileşenlerin İngiltere faiz oranına bağlı olması

Faiz oranını "finansal araç" sınıfının bir üyesi yapardım ve bunu herhangi bir üye sınıfına (hesaplama başına ya da inşaatta ona bir işaretçi / kanca vererek) geçirmeniz gerektiğini kabul ediyorum.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.