“Derin kompozisyon hiyerarşileri” de kötü değil mi?


19

"Kompozisyon Hiyerarşisi" bir şey değilse özür dilerim, ama soruda ne demek istediğimi açıklayacağım.

"Kalıtım hiyerarşilerini düz tut" veya "Kompozisyonu kalıtım yerine tercih et" gibi bir varyasyonla karşılaşmamış hiçbir OO programcısı yoktur. Bununla birlikte, derin kompozisyon hiyerarşileri de sorunlu görünmektedir.

Diyelim ki bir deneyin sonuçlarını ayrıntılandıran bir rapor koleksiyonuna ihtiyacımız var:

class Model {
    // ... interface

    Array<Result> m_results;
}

Her sonucun belirli özellikleri vardır. Bunlar, deneyin zamanının yanı sıra deneyin her aşamasından bazı meta verileri içerir:

enum Stage {
    Pre = 1,
    Post
};

class Result {
    // ... interface

    Epoch m_epoch;
    Map<Stage, ExperimentModules> m_modules; 
}

Tamam harika. Şimdi, her deney modülünde, deneyin sonucunu açıklayan bir dizenin yanı sıra deneysel örnek setlerine referansların bir koleksiyonu bulunmaktadır:

class ExperimentalModules {
    // ... interface

    String m_reportText;
    Array<Sample> m_entities;
}

Ve sonra her numunenin ... iyi, resmi elde.

Sorun şu ki, benim uygulama etki alanından nesneleri modelleme, bu çok doğal bir uyum gibi görünüyor, ama günün sonunda, bir Resultsadece aptal veri kapsayıcısı! Bunun için büyük bir sınıf grubu oluşturmak faydalı görünmüyor.

Yukarıda gösterilen veri yapıları ve sınıflarının uygulama alanındaki ilişkileri doğru bir şekilde modellediğini varsayarsak, derin bir kompozisyon hiyerarşisine başvurmadan böyle bir "sonucu" modellemek için daha iyi bir yol var mı? Böyle bir tasarımın iyi olup olmadığını belirlemenize yardımcı olacak herhangi bir dış bağlam var mı?


Dış bağlam bölümünü anlama.
Tulains Córdova

@ TulainsCórdova burada sormaya çalıştığım şey "derin kompozisyonun iyi bir çözüm olduğu durumlar var mı?"
AwesomeSauce

Bir cevap ekledim.
Tulains Córdova

5
Evet kesinlikle. İnsanların kalıtımı kompozisyonla değiştirerek çözmeye çalıştıkları sorunlar, sadece bir özellik toplama stratejisini diğeri için değiştirdiğiniz için sihirli bir şekilde ortadan kalkmaz. İkisi de karmaşıklığı yönetmeye yönelik çözümlerdir ve bu karmaşıklık hala oradadır ve bir şekilde ele alınması gerekir.
Mason Wheeler

3
Derin veri modellerinde yanlış bir şey görmüyorum. Ama aynı zamanda bunu kalıtımla nasıl modelleyebileceğinizi de göremiyorum çünkü her katmanda 1: N ilişkisi var.
usr

Yanıtlar:


17

Bu nedir Demeter / az bilginin prensibi kanunu ile ilgili. Bir kullanıcı Modelmutlaka ExperimentalModulesçalışmalarını yapmak için 'arayüz' bilmek zorunda olmamalıdır .

Genel sorun, bir sınıf başka bir türden miras aldığında veya bir tür ile ortak bir alana sahip olduğunda veya bir yöntem bir türü parametre olarak aldığında veya bir tür döndürdüğünde, tüm bu türlerin arayüzlerinin sınıfımın etkin arayüzünün bir parçası haline gelmesidir. Soru şu oluyor: bağlı olduğum bu türler: bunları sınıfımın bütün noktası mı kullanıyor? Yoksa sadece kazara açığa çıkardığım uygulama ayrıntıları mı? Çünkü bunlar uygulama ayrıntılarıysa, onları açığa çıkardım ve sınıfımdaki kullanıcıların bunlara bağımlı olmalarına izin verdim - müşterilerim artık uygulama ayrıntılarıyla sıkı sıkıya bağlı.

Dolayısıyla, uyumu iyileştirmek istersem, kullanıcıların özel yapılarıma erişmesini istemek yerine, yararlı şeyler yapan daha fazla yöntem yazarak bu bağlantıyı sınırlayabilirim. Burada, sonuçları aramak veya filtrelemek için yöntemler sunabiliriz. Artık arayüzümde bir değişiklik olmadan iç temsili değiştirebildiğim için sınıfımı yeniden düzenlemeyi kolaylaştırıyor.

Ama bu maliyetsiz değil - maruz kalan sınıfımın arayüzü artık her zaman gerekli olmayan operasyonlarla şişiriliyor. Bu, Arabirim Ayrıştırma İlkesini ihlal ediyor: Kullanıcıları gerçekte kullandıklarından daha fazla işleme bağımlı olmaya zorlamamalıyım. İşte tasarımın önemli olduğu yer: Tasarım, bağlamınızda hangi ilkenin daha önemli olduğuna karar vermek ve uygun bir uzlaşma bulmakla ilgilidir.

Birden çok sürümde kaynak uyumluluğunu sürdürmesi gereken bir kitaplık tasarlarken, en az bilgi ilkesini daha dikkatli bir şekilde izlemeye daha meyilli olurum. Kitaplığım dahili olarak başka bir kitaplık kullanıyorsa, o kitaplık tarafından tanımlanan hiçbir şeyi kullanıcılarıma asla göstermem. İç kütüphaneden bir arabirim göstermem gerekirse, basit bir sarma nesnesi oluştururdum. Köprü Deseni veya Cephe Deseni gibi Tasarım Desenleri burada yardımcı olabilir.

Ancak arayüzlerim yalnızca dahili olarak kullanılıyorsa veya ortaya koyacağım arayüzler çok temel ise (standart bir kütüphanenin veya onu değiştirmek için hiçbir zaman mantıklı olmayacak kadar temel bir kütüphanenin parçası), o zaman gizlemek işe yaramaz olabilir bu arayüzler. Her zamanki gibi, herkese uyan tek bir cevap yoktur.


Sahip olduğum büyük bir endişeden bahsettiniz; daha yüksek soyutlama seviyelerinde faydalı bir şey yapmak için uygulamaya çok yaklaşmak zorunda olduğum fikri. Çok faydalı bir tartışma, teşekkürler.
AwesomeSauce

7

“Derin kompozisyon hiyerarşileri” de kötü değil mi?

Elbette. Kural aslında "tüm hiyerarşileri olabildiğince düz tut" demelidir.

Ancak derin kompozisyon hiyerarşileri, derin miras hiyerarşilerinden daha az kırılgandır ve değişmesi daha esnektir. Sezgisel olarak, bu bir sürpriz olmamalıdır; aile hiyerarşileri aynı şekilde. Kan akrabalarınızla ilişkiniz genetikte sabittir; arkadaşlarınızla ve eşinizle olan ilişkileriniz değildir.

Örneğiniz bana “derin hiyerarşi” olarak çarpmıyor. Bir form, x ve y koordinatlarından miras kalan bir dizi noktadan miras alan bir dikdörtgenden miras alır ve henüz tam bir buhar kafasını bile almadım.


4

Tekrarlama Einstein:

tüm hiyerarşileri olabildiğince düz tutun, ancak düzleştirmeyin

Yani, modellemekte olduğunuz sorun böyleyse, onu olduğu gibi modelleme konusunda bir sorun yaşamamalısınız.

Uygulama sadece dev bir e-tablo idi, o zaman kompozisyon hiyerarşisini olduğu gibi modellemek zorunda değilsiniz. Aksi takdirde yapın. Bu şeyin sonsuz derinlikte olduğunu sanmıyorum. Bu tür koleksiyonları doldurmak pahalıysa, koleksiyonları tembel hale getiren alıcıları pahalı tutun, örneğin onları bir veritabanı oluşturmak için çeken bir depoya istemek gibi. Tembel derken, ihtiyaç duyulana kadar onları doldurmayın.


1

Evet, ilişkisel tablolar gibi modelleyebilirsiniz

Result {
    Id
    ModelId
    Epoch
}

vb. genellikle daha kolay programlamaya ve bir veritabanıyla basit eşleştirmeye yol açabilir. fakat ilişkilerinizin zor kodlamasını kaybetme pahasına


0

Java'da bunu nasıl çözeceğimi gerçekten bilmiyorum, çünkü Java her şeyin bir nesne olduğu fikri etrafında inşa edilmiştir. Veri bloklarınızdaki türler heterojen olduğundan (zaman damgası + liste veya dize + liste ... gibi) ara sınıfları bir sözlükle değiştirerek bastıramazsınız. Bir kap sınıfını kendi alanı ile değiştirmenin alternatifi (örn. "M_epoch" değişkeni ile "m_modüller" ile geçmek) basittir, çünkü örtülü bir nesne (diğeri olmadan bir tane olamaz) yarar.

Önceliklendirme dilimde (Python), başparmağım, belirli bir mantık (temel alma ve ayarlama hariç) ona ait değilse bir nesne oluşturmamak olacaktır. Ancak kısıtlamalarınız göz önüne alındığında, sahip olduğunuz kompozisyon hiyerarşisinin mümkün olan en iyi tasarım olduğunu düşünüyorum.

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.