Nesne Sınırlarında Bilgi Dökülmesi


10

Çoğu zaman iş nesnelerim, bilginin nesne sınırlarını çok sık aşması gereken durumlara sahip olma eğilimindedir. OO yaparken, bilgilerin bir nesnede olmasını ve bu bilgilerle ilgili tüm kodların o nesnede olabildiğince fazla olmasını istiyoruz. Ancak iş kuralları bu ilkeye uymuyor ve bana sorun çıkarıyor.

Örnek olarak, bir fiyatı olan bir InventoryItem anlamına gelen bir dizi OrderItems içeren bir Siparişimiz olduğunu varsayalım. InventoryItem.GetPrice () ile bir miktarı çarpan OrderItem.GetPrice () sonucunu toplayan Order.GetTotal () işlevini çağırıyorum. Çok uzak çok iyi.

Ama sonra bazı eşyaların bir anlaşma için iki ile satıldığını öğreniyoruz. OrderItem.GetPrice () öğesinin InventoryItem.GetPrice (miktar) gibi bir şey yapmasını ve InventoryItem'in bununla ilgilenmesine izin vererek bunu halledebiliriz.

Ancak, iki-bir-bir anlaşmanın sadece belirli bir süre için devam ettiğini öğreniyoruz. Bu zaman dilimi siparişin tarihini temel almalıdır. Şimdi OrderItem.GetPrice () öğesini InventoryItem.GetPrice olarak değiştiriyoruz (quatity, order.GetDate ())

Ancak, müşterinin sistemde ne kadar süredir bulunduğuna bağlı olarak farklı fiyatları desteklememiz gerekir: InventoryItem.GetPrice (miktar, order.GetDate (), order.GetCustomer ())

Ancak, iki-bir-bir anlaşmanın sadece aynı envanter öğesinin birden fazlasını satın almak için değil, aynı zamanda bir InventoryCategory içindeki herhangi bir öğe için birden fazla satın almak için geçerli olduğu ortaya çıkıyor. Bu noktada ellerimizi atıyoruz ve sadece InventoryItem'e sipariş öğesini veriyoruz ve ihtiyaçlarını almak için erişimciler aracılığıyla nesne referans grafiğinin üzerinden geçmesine izin veriyoruz: InventoryItem.GetPrice (this)

TL; DR Nesnelerde düşük bağlantım olmasını istiyorum, ancak iş kuralları genellikle belirli kararlar alabilmek için her yerden bilgiye erişmeye zorluyor.

Bununla başa çıkmak için iyi teknikler var mı? Diğerleri de aynı sorunu bulur mu?


4
İlk bakışta InventoryItem sınıfının fiyatı hesaplayarak çok fazla şey yapmaya çalıştığı görülüyor, belirli bir fiyatı iade etmek bir şey ama satış fiyatları ve özel iş kuralları InventoryItem'de adres olmamalı. Fiyatlarınızı hesaplamak için bir sınıf hazırlayın ve Sipariş, Envanter ve Müşteri vb.
Chris

@Chris, evet, fiyatlandırma mantığını bölmek muhtemelen iyi bir fikirdir. Benim sorunum böyle bir nesne sipariş ile ilgili tüm nesnelere sıkıca bağlı olmasıdır. Bu beni rahatsız eden ve kaçınabileceğimi merak ettiğim kısım.
Winston Ewert

1
Bir şey, herhangi bir şey demek istemiyorum, tüm bu bilgilere ihtiyaç duyuyorsa, bir şekilde istenen sonucu üretmek için bu bilgileri tüketmesi gerekir. Önceden oluşturulmuş envanter, ürün, müşteri vb. Varsa, iş mantığını kendi alanında uygulamak en mantıklıdır. Gerçekten daha iyi bir çözümüm yok.
Chris

Yanıtlar:


6

Temelde çalıştığım yerde aynı deneyime sahibiz ve bunu OrderBusinessLogic sınıfına sahip olarak ele aldık. Çoğunlukla, tanımladığınız düzen, işimizin çoğunluğu için işe yarar. Güzel, temiz ve basit. Ancak, bu kategoriden herhangi bir 2 satın aldığınız okkaizyonlarda, bunu bir "iş yürütme" olarak ele alıyoruz ve OrderBL sınıfının gerekli nesneleri gezerek toplamları yeniden hesaplamasını sağlıyoruz.

Mükemmel bir çözüm mü, hayır. Hâlâ bir sınıfımız var, diğer sınıflar hakkında çok fazla şey biliyor, ama en azından bu ihtiyacı iş nesnelerinden ve bir iş mantığı sınıfına taşıdık.


2
Şüphe duyduğunuzda başka bir sınıf ekleyin.
Chris

1

Senin gibi Sesler tüm bu şeyler izler ayrı İndirim nesnesi (veya onların bir listesini) gerekir ve sonra bir şey gibi Siparişine İndirim (ler) uygulamak Order.getTotal(Discount)ya Discount.applyTo(Order)veya benzer.


Envanter nesnesi yerine bir indirim koymak kodu daha iyi olacağını görebilirsiniz. Ancak, görünen indirim nesnesi, işini yapmak için tüm farklı nesnelerden bilgilere erişmek zorunda kalacak. Yani bu, en azından görebildiğim kadarıyla sorunu çözmüyor.
Winston Ewert

2
Ben İndirim nesnesi iyi bir fikir olduğunu düşünüyorum, ama ben bir gözlemci desen ( en.wikipedia.org/wiki/Observer_pattern ), desen desen (ler)
BlackICE

1

Diğer sınıflardan verilere erişmek son derece uygundur. Ancak bunun tek yönlü bir ilişki olmasını istiyorsunuz. Örneğin, ClassOrder öğesinin CallItem'e eriştiğini varsayalım. İdeal olarak, ClassItem ClassOrder erişmemelidir. Sipariş Sınıfınızda eksik olduğunu düşündüğüm, Walter'ın önerdiği gibi bir sınıfı garanti edebilecek veya etmeyecek bir tür iş mantığı.

Edit: Winston kullanıcısının yorumuna yanıt

Hiç bir envanter öğesi nesnesine ihtiyacınız olduğunu sanmıyorum ... en azından onu kullandığınız şekilde. Bunun yerine bir envanter veritabanı yöneten bir envanter sınıfı olurdu.

Bir kimlikle envanter öğelerine atıfta bulunacağım. Her sipariş, envanter kimliklerinin bir listesini ve karşılık gelen bir miktarı içerir.

Sonra siparişin toplamını böyle bir şeyle hesaplardım.
Inventory.GetCost (Öğeler, customerName, tarih)

Sonra başka bir yardımcı işlevi olabilir:

Inventory.ItemsLefts (int itemID)
Inventory.AddItem (int itemID, int miktar)
Inventory.RemoveItem (int itemID, int miktar)
Inventory.AddBusinessRule (...)
Inventory.DeleteBusinessRule (...)


Yakından ilişkili sınıflardan veri istemek gayet iyi. Dolaylı olarak ilişkili sınıflardan verilere eriştiğimde sorun ortaya çıkıyor. Bu mantığı Order sınıfında uygulamak için Order sınıfının doğrudan Envanter nesnesiyle (gerekli fiyatlandırma verilerini içeren) ilgilenmesini gerektirir. Beni rahatsız eden kısım budur çünkü Order'ı (ideal olarak) hakkında hiçbir şey bilmeyecek sınıflara bağlar.
Winston Ewert

Temel olarak, fikriniz OrderItem'i ortadan kaldırmak olacaktır, bunun yerine Order tüm bu bilgileri izler. Daha sonra bu bilgileri fiyatlandırma için başka bir nesneye aktarmak kolaydır. Bu işe yarayabilir. (Belirli senaryoda bu örnek, OrderItem'in çok karmaşık ve gerçekten kendi nesnesi olması gerektiğine dayanmaktadır)
Winston Ewert

Bana mantıklı gelmeyen neden, Envanter'e nesne referansları yerine kimlik numaraları kullanılarak referans verilmesini istediğinizdir. Nesne referanslarını ve miktarlarını sonra öğe kimlikleri ve referanslarını takip etmek benim için daha iyi görünüyor.
Winston Ewert

Bunu gerçekten önermiyorum. Sipariş öğeleri için hala bir sınıf veya yapıya sahip olmanız gerektiğini düşünüyorum. Ben sadece tek bir envanter öğe nesneleri esas olarak içinde fiyat olması gerektiğini düşünmüyorum çünkü nasıl bir tür veritabanı soran dışarı orada alacağından emin değilim. Sipariş veya envanter öğesi kesinlikle bir öğe tanımlayıcısı ve bir miktar içeren bir veri sınıfı olacaktır. Siparişin kendisinde bu nesnelerin bir listesi bulunur.
Ocak'ta

İkinci yorumda ne istediğini gerçekten bilmiyorum. Her şeyin bir nesne olması gerekmez. Gerçekten bir tür kimliği olmayan belirli bir öğeyi nasıl bulacağınızdan emin değilim.
Pemdas

0

Bunu daha düşündükten sonra, kendi alternatif stratejimi buldum.

Bir Fiyat sınıfı tanımlayın. Inventory.GetPrice()bir fiyat nesnesi döndürür

Price OrderItem::GetPrice()
{
    return inventory.GetPrice().quantity(quantity);
}

Currency OrderItem::GetTotal()
{
    Price price = empty_price();
    for(item in order_items)
    {
         price = price.combine( item.GetPrice() )
    }
    price = price.date(date).customer(customer);
    return price.GetActualPrice();
}

Şimdi Price sınıfı (ve muhtemelen bazı ilgili sınıflar) fiyatlandırma mantığını kapsamaktadır ve düzen bunun için endişelenmek zorunda değildir. Fiyat, Order / OrderItem hakkında hiçbir şey bilmez, bunun yerine sadece bilgi beslenir.

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.