SOLID ilkelerinin bazılarının veya tamamının kodu temizlemek için antitetik olduğu OOP tatları var mı?


26

Geçenlerde video oyun geliştirmede OOP hakkında bir arkadaşımla bir tartışma yaptım.

Arkadaşlarımın sürprizine göre, birçok küçük sınıf ve birkaç soyutlama katmanı içeren oyunlarımdan birinin mimarisini açıklıyordum. Bunun, her şeye Tek Sorumluluk vermeye ve aynı zamanda bileşenler arasındaki eşleşmeyi gevşetmeye odaklanmamın sonucu olduğunu savundum.

Endişesi, çok sayıda sınıfın bir bakım kabusuna dönüşmesiydi. Benim görüşüme göre tam tersi etkiye sahip olacağıydı. Bunu, yüzyıllar gibi görünen ve sonunda katılmayacağımızı kabul ederek, belki de SOLID ilkelerinin ve uygun OOP'un gerçekten iyi bir şekilde karışmadığı durumlar olduğunu söyleyerek tartışmaya devam ettik.

SOLID ilkeleriyle ilgili Wikipedia yazısı bile, bakım kodunu yazmaya yardımcı olan kılavuzlar olduklarını ve genel bir çevik ve uyarlanabilir programlama stratejisinin bir parçası olduklarını belirtir.

Yani benim sorum şu:

OID'de, SOLID ilkelerinin bir kısmının veya tamamının, kodu temizlemek için kendilerini ödünç vermediği durumlar var mı?

Liskov Değişim İlkesinin muhtemelen başka bir güvenli miras lezzetiyle çatışabileceğini hayal edebiliyorum. Diğer bir deyişle, eğer birileri miras yoluyla uygulanan başka bir faydalı örüntü geliştirmişse, LSP'nin onunla doğrudan çatışması olabilir.

Diğerleri var mı Belki de belirli proje türleri veya belirli hedef platformlar daha az SOLID yaklaşımıyla daha iyi çalışır?

Düzenle:

Kodumu nasıl geliştireceğimi sormayacağımı belirtmek isterim;) Bu soruda bir projeden bahsetmemin tek nedeni küçük bir bağlam vermekti. Benim sorum genel olarak OOP ve tasarım ilkeleri hakkında .

Projemi merak ediyorsanız, bunu görün .

Düzenleme 2:

Bu sorunun 3 yoldan biriyle cevaplanacağını hayal ettim:

  1. Evet, kısmen SOLID ile çatışan OOP tasarım ilkeleri mevcut
  2. Evet, SOLID ile tamamen çelişen OOP tasarım ilkeleri mevcut
  3. Hayır, SOLID arının dizleridir ve OOP sonsuza dek daha iyi olacak. Ancak, her şeyde olduğu gibi, her derde deva değil. Ayarında içmek.

Seçenek 1 ve 2 muhtemelen uzun ve ilginç cevaplar vermiş olacaktı. Seçenek 3 ise, kısa, ilgi çekici olmayan ancak genel olarak güven verici bir cevap olacaktır.

Seçenek 3'e yaklaşıyor gibiyiz.


'Temiz kodu' nasıl tanımlarsınız?
GrandmasterB

Temiz kod, bu soru kapsamında, OOP'nin hedeflerini ve seçilen tasarım ilkelerini karşılayacak şekilde kod yapısıdır. Bu yüzden, OOP + SOLID tarafından belirlenen hedefler açısından temiz kodları biliyorum. OOP ile çalışan ancak SOLID ile tamamen veya kısmen uyumlu olmayan başka bir tasarım ilkeleri seti olup olmadığını merak ediyorum.
MetaFight

1
Bu oyununun performansı hakkında başka hiçbir şeyden çok endişeliyim. Metin tabanlı oyundan bahsetmiyorsak.
Euphoric

1
Bu oyun aslında bir deneydir. Farklı gelişim yaklaşımları deniyorum ve ayrıca oyun yazarken enterprise-y kodunun çalışıp çalışmayacağını da görmeye çalışıyorum. Performansın bir sorun olmasını bekliyorum, ancak henüz olmadı. Olursa / deneyeceksem, deneyeceğim bir sonraki şey kodumu nasıl performans koduna uyarlayacağım. Çok fazla öğrenme!
MetaFight

1
Bazı indirgemelerin riski altında, "Neden" sorusuna geri dönmek istiyorum: Oyun gelişiminde OOP . Oyun geliştirmenin doğası gereği, “geleneksel” OOP, örneğin burada ilginç bir değişken olan varlık / bileşen sistemlerinin çeşitli tatları lehine moda düşüyor gibi görünüyor . Bu daha çok, bana "SOLID + OOP" değil, "OOP + Oyun Geliştirme" olması gerektiğini düşündürüyor. Oyun dev için nesne etkileşimi grafiğine baktığınızda. vs. diyor ki, N-katmanlı uygulama, farklılıklar yeni bir paradigmanın iyi olduğu anlamına gelebilir.
J Trana

Yanıtlar:


20

OID'de, SOLID ilkelerinin bir kısmının veya tamamının, kodu temizlemek için kendilerini ödünç vermediği durumlar var mı?

Genel olarak hayır. Tarihçe, SOLID ilkelerinin büyük ölçüde artmış dekuplaj işlemine katkıda bulunduğunu göstermiştir; bu da kodda esnekliği ve dolayısıyla değişime uyum sağlama yeteneğinizi arttırmanın yanı sıra kodun nedenini anlama, test etme, yeniden kullanma becerisini arttırdığını göstermiştir. Kısacası, kodunuzu daha temiz hale getirin.

Şimdi, SOLID ilkelerinin DRY (kendinizi tekrar etme), KISS (basit aptal tutma) veya iyi OO tasarımının diğer prensipleriyle çarpıştığı durumlar olabilir. Ve elbette gereksinimlerin gerçekliği, insanların kısıtlamaları, programlama dillerimizin kısıtlamaları, diğer engellerle çarpışabilirler.

Kısacası, SOLID ilkeleri her zaman kodu temizlemeye kendilerini ödünç verir, ancak bazı senaryolarda birbiriyle çelişen alternatiflerden daha az borç verir. Her zaman iyidirler, ama bazen diğer şeyler daha iyidir.


14
Sevdim ama bazen başka şeyler daha iyi . Bir "Hayvan Çiftliği" hissi var. ;)
Sinir

12
+1 Sadece SOLID ilkelerine baktığımda, 5 tane "iyi kalpli" görüyorum. Fakat hiçbiri en iyi KURU, KISS ve "niyetlerini netleştirmedi". SOLID kullanın, ancak biraz dikkat ve şüphecilik gösterin.
user949300

Katılıyorum. Açıkça takip edilmesi gereken doğru ilkelerin durumlara bağlı olduğunu düşünüyorum, ancak her zaman her şeyin üzerinde yer alan zorlu performans gerekliliklerinin yanı sıra (özellikle oyun geliştirmede önemli olan), DRY ve KISS'in genellikle daha önemli olduğunu düşünüyorum. SOLID’den Elbette, kodu ne kadar temiz yaparsanız, kodu o kadar iyi hale getirirsiniz, bu nedenle tüm ilkeleri çatışma olmadan izleyebilirseniz, o kadar iyi.
Ben Lee,

Entegrasyon ayrımına karşı toplam agrega tasarımına ne dersiniz? Temel "dizi" arayüzü [örneğin IEnumerable] , ve gibi Countve [geri dönüşü gibi şeylerin "verimli" olup olmadığını gösterecek ] gibi asImmutableözellikleri içeriyorsa , o zaman biri birden fazla dizi alan ve bunları toplayan statik bir yönteme sahip olabilir. Tek bir uzun sekans gibi davranacağım. Bu tür yetenekler temel sıralama türünde mevcutsa, yalnızca varsayılan uygulamalara zincir halinde olsalar bile, bir toplama bu yetenekleri ortaya çıkarabilir ...getAbilitiesCount
supercat

... ve bunları yapabilen temel sınıflarla birlikte kullanıldığında verimli bir şekilde uygulayın. Biri, sayımını bilen on milyonluk bir öğe listesi ve yalnızca sıralı olarak öğeleri alabilen beş öğe listesi toplarsa, 10.000.003. giriş için bir istek, ilk listeden sayımı okumalı ve ardından ikinci listeden üç maddeyi okumalıdır. . Mutfak lavabosu arayüzleri ISS'yi ihlal edebilir, ancak bazı kompozisyon / toplama senaryolarının performansını büyük ölçüde artırabilir.
supercat

13

Hem finans hem de oyunlarda çalıştığım konusunda alışılmadık bir bakış açım olduğunu düşünüyorum.

Oyunlarda tanıştığım programcıların çoğu Yazılım Mühendisliğinde berbattı - ama SOLID gibi uygulamalara ihtiyaçları yoktu. Geleneksel olarak, oyunlarını bir kutuya koyarlar - sonra bittiler.

Finansta, geliştiricilerin gerçekten özensiz ve disiplinsiz olabileceğini keşfettim, çünkü oyunlarda yaptığınız performansa ihtiyaçları yok.

Yukarıdaki ifadelerin her ikisi de elbette aşırı genellemelerdir, ancak aslında her iki durumda da temiz kod önemlidir. Optimizasyon için açık ve anlaşılması kolay kod önemlidir. Sürdürülebilirlik aşkına, aynı şeyi istiyorsun.

Bu, SOLID'in eleştirisiz olmadığını söylemek değildir. İlke olarak adlandırılıyorlar ve yine de kurallara uymaları gerekiyor mu? Peki tam olarak ne zaman onları takip etmeliyim? Kuralları ne zaman çiğnemeliyim?

Muhtemelen iki kod parçasına bakabilir ve hangisinin SOLID'e en uygun olduğunu söyleyebilirsiniz. Ancak izolasyonda, kodu SOLID olacak şekilde dönüştürmenin nesnel bir yolu yoktur. Bu kesinlikle geliştiricinin yorumu içindir.

"Çok sayıda sınıf bir bakım kabusuna yol açabilir" demenin bir sakıncası yoktur. Bununla birlikte, eğer SRP doğru bir şekilde yorumlanmazsa, kolayca bu soruna yol açabilirsiniz.

Çok fazla sorumluluğu olmayan birçok katmana sahip kod gördüm. Ayrı bir şey yapmayan sınıflar bir durumdan diğerine geçiş halini alır. Çok fazla dolaylı katmanın klasik problemi.

Eğer kötüye kullanılırsa SRP, kodunuzdaki uyum eksikliği ile sonuçlanabilir. Bir özellik eklemeye çalıştığınızda bunu söyleyebilirsiniz. Her zaman aynı anda birkaç yeri değiştirmek zorunda kalırsanız, kodunuzda uyum yoktur.

Açık-Kapalı, eleştirmenleri olmadan değildir. Örneğin, Jon Skeet'in Açık Kapalı prensibini incelemesine bakınız . Burada iddialarını tekrarlamayacağım.

LSP hakkındaki argüman varsayımsal görünüyor ve başka bir güvenli miras yolu ile ne demek istediğinizi gerçekten anlamıyorum?

ISS, SRP'yi biraz kopyalamış gibi görünüyor. Şüphesiz onlar, arayüzünüzdeki tüm müşterilerin ne yapacaklarını asla tahmin edemeyeceğiniz şekilde yorumlanmalıdır. Bugünün uyumlu arayüzü yarının ISS ihlalidir. Mantıksız tek sonuç, arayüz başına birden fazla üyeye sahip olmamak.

DIP kullanılamaz koda yol açabilir. DIP adına çok sayıda parametre içeren sınıflar gördüm. Bu sınıflar normalde kompozit parçalarını "yeniledi", ama ben test kabiliyetinin adı bir daha asla yeni anahtar kelimeyi kullanmamalıyız.

SOLID kendi başına temiz kod yazmanız için yeterli değildir. Robert C. Martin'in “ Temiz Kod: Çevik Yazılım İşçiliğinin El Kitabı ” kitabını gördüm . Bununla ilgili en büyük sorun, bu kitabı okumak ve onu kurallar olarak yorumlamak kolaydır. Bunu yaparsanız, noktayı kaçırıyorsunuz. Çok sayıda koku, buluşsal yöntem ve ilke içerir - bunların hepsi SOLID'den beşinden daha fazlasıdır. Tüm bu 'ilkeler' gerçekten ilkeler değil, ilkelerdir. Bob Amca, onları kavramlar için "küçük delikler" olarak görüyor. Onlar dengeleyici bir eylemdir; Herhangi bir kılavuza kör bir şekilde uyulması sorunlara neden olacaktır.


1
Çok sayıda yapıcı parametreniz varsa, SRP'yi ihlal ettiğinizi gösterir. Yine de bir DI konteyneri zaten çok sayıda yapıcı parametresi ile bağlantılı acıyı ortadan kaldırıyor, bu yüzden DIP hakkındaki ifadelerinize katılmıyorum.
Stephen

Tüm bu 'ilkeler' gerçekten ilkeler değil, ilkelerdir. Onlar dengeleyici bir eylemdir; SRP'yi takip eden yazımda da söylediğim gibi aşırı uç sorunlu olabilir.
Dave Hillier

İyi cevap, +1. Eklemek istediğim bir şey: Skeet'in incelemesini, OCP'nin arkasındaki temel fikirlerden değil, standart ders kitaplarının OCP tanımının bir eleştirmeni olduğunu okudum. Anladığım kadarıyla, korunan varyasyon fikri, OCP'nin en baştan olması gerektiği şeydi.
Doktor Brown,

5

İşte benim görüşüm:

Her ne kadar SOLID ilkeleri yedekli ve esnek olmayan bir kod temeli oluştursa da, çok fazla sınıf ve katman varsa, bu okunabilirlik ve bakımda bir denge olabilir.

Özellikle soyutlama sayısıyla ilgili . Birkaç soyutlamaya dayanıyorlarsa çok sayıda sınıf iyi olabilir. Projenizin boyutunu ve özelliklerini bilmediğimiz için, söylemesi zor, ama çok sayıda sınıfa ek olarak birkaç katmandan bahsetmeniz biraz endişe verici .

Sanırım SOLID ilkeleri OOP ile aynı fikirde değil, ancak bunlara bağlı kalarak temiz olmayan kodlar yazmak hala mümkün.


3
+1 Tanım olarak, neredeyse esnek bir sistem, daha az esnek olan sistemden daha az bakım gerektirebilir olmalıdır. Getirdiği ilave karmaşıklık nedeniyle esneklik bir maliyetle geliyor.
Andy

@Andy mutlaka değil. şu anki işimde, kodun en kötü kısımlarının çoğu dağınık, çünkü sadece "basit bir şey yaparak, sadece birlikte kesmek ve çalışmasını sağlamak, böylece karmaşıklaşmaması için" atılıyor. Sonuç olarak, sistemin çoğu parçası% 100 katıdır. Büyük bölümlerini yeniden yazmadan onları hiçbir şekilde değiştiremezsiniz. Bakımı gerçekten zor. Bakım, sistemin ne kadar esnek olmasından değil, yüksek uyum ve düşük bağlantıdan gelir.
sara

3

Gelişmekte olan ilk günlerimde C ++ 'da Roguelike yazmaya başladım. Eğitimimden öğrendiğim iyi nesne yönelimli metodolojiyi uygulamak istediğim için hemen oyunun C ++ nesnesi olduğunu gördüm. Potion, Swords, Food, Axe, JavelinsGibi tüm temel bir çekirdek türetilen Itemadı, simge, ağırlık, bu tür şeyler taşıma, kod.

Sonra, çanta mantığını kodladım ve bir sorunla karşılaştım. Torbaya koyabilirim Items, ama sonra bir tane seçersem, a Potionveya a olup olmadığını nasıl bilebilirim Sword? İnternette eşyaların nasıl indirileceğini araştırdım. Çalışma zamanı bilgisini etkinleştirmek için derleyici seçeneklerinden hackledim, bu yüzden soyutlanmış Itemgerçek tiplerimin ne olduğunu bilirim ve hangi işlemlere izin vereceğimi bilmek için tipler üzerinde mantık açmaya başladım (örneğin, içmemek Swordsve Potionsayaklarımı asmak)

Temel olarak kodu yarı-kopyalanmış çamurdan oluşan büyük bir top haline getirdi. Proje devam ederken, tasarımdaki başarısızlığın ne olduğunu anlamaya başladım. Olan, değerleri temsil etmek için sınıfları kullanmaya çalıştım. Sınıf hiyerarşim anlamlı bir soyutlama değildi. Ne ben yapmalıydım yapıyor Itemgibi fonksiyonlar, bir dizi uygulamak Equip (), Apply ()ve Throw (), ve değerlere dayalı her davranmaya olun. Equip slotları temsil etmek için enums kullanmak. Farklı silah türlerini temsil etmek için enums kullanmak. Daha fazla değer ve daha az sınıflandırma kullanmak, çünkü alt sınıflamamın bu son değerleri doldurmaktan başka bir amacı yoktu.

Bir soyutlama katmanı altında nesne çarpımına maruz kaldığınız için, görüşümün burada değerli olabileceğini düşünüyorum. Çok fazla nesne türüne sahipseniz, nelerin değere sahip olması gerekenlerin tipleriyle karıştırdığınızı düşünebilirsiniz.


2
Sorun, tiplerin değer sınıfları ile karıştırılmasıydı (not: OOP / C ++ sınıf kavramına atıfta bulunmak için class kelimesini kullanmıyorum.) Kartezyen bir düzlemde bir noktayı temsil etmenin birden fazla yolu var (dikdörtgen koordinatlar, kutup koordinatlar) fakat hepsi aynı tipte. Ancak, genel kullanıma yönelik OOP dilleri, değerlerin doğal olarak sınıflandırılmasını desteklemez. Buna en yakın şey, C / C ++ 'ın birliğidir, ancak ne halt koyduğunuzu bilmek için fazladan bir alan eklemeniz gerekir.
Doval

4
Deneyiminiz örnek olarak kullanılabilir. SOLID veya herhangi bir modelleme metodolojisini kullanarak, sürdürülemez ve genişletilemez bir kod yarattınız.
Euphoric

1
@Euphoric Çok çalıştım. Nesneye yönelik bir metodolojim vardı. Yine de bir metodolojiye sahip olmak ve başarılı bir şekilde uygulamak arasında bir fark var :)
Arthur Havlicek

2
Bu, OOP'deki temiz koda aykırı olarak çalışan bir SOLID ilkesi örneği nasıldır? Yanlış bir tasarım örneği gibi görünüyor - bu OOP'a dik!
Andres F.

1
Temel ITEM sınıfınız, FALSE olarak varsayılan olan birkaç "canXXXX" boolean yöntemine sahip olmalıydı. Daha sonra Javelin sınıfınızda true değerini döndürmek için "canThrow ()" ve Postion sınıfınız için true değerini döndürmek için canEat () öğesini ayarlayabilirsiniz.
James Anderson

3

Endişesi, çok sayıda sınıfın bir bakım kabusuna dönüşmesiydi. Benim görüşüme göre tam tersi etkiye sahip olacağıydı.

Kesinlikle arkadaşınızın yanındayım, ancak bu bizim etki alanlarımız, çözdüğümüz sorun ve tasarım türleri ve özellikle gelecekte hangi tür şeyleri gerektirmesi muhtemeldir. Farklı problemler, farklı çözümler. Doğru ya da yanlış olduğuna inanmıyorum, sadece programcılar kendi tasarım problemlerini en iyi şekilde çözebilecekleri en iyi yolu bulmaya çalışıyorlar. Oyun motorlarına pek benzemeyen VFX'te çalışıyorum.

Ancak, en azından bir şekilde KATI uyumlu bir mimariden (COM tabanlı) daha fazla olarak adlandırılabilecek bir şeyle mücadele ettiğim sorun, kabaca "çok fazla sınıf" veya "çok fazla işlev" olarak kaynamış olabilir. Arkadaşın tarif edebilir. Özellikle, "çok fazla etkileşim, çok fazla yaramazlık yapabilecek çok fazla yer, yan etkilere neden olabilecek çok fazla yer, değişmesi gerekebilecek çok fazla yer ve onların yaptıklarını düşünmeyecek çok fazla yer" diyeceğim. ."

Bir tekne yükü alt tipi tarafından uygulanan bir avuç soyut (ve saf) arayüzümüz vardı (bu şemayı ECS'in yararları hakkında konuşmak bağlamında sol alt yorumu dikkate almayın):

görüntü tanımını buraya girin

Bir hareket arayüzü veya bir sahne düğümü arayüzünün yüzlerce alt tip tarafından uygulanabileceği yerler: ışıklar, kameralar, kafesler, fizik çözücüler, gölgelendiriciler, dokular, kemikler, ilkel şekiller, eğriler vb. ). Ve asıl sorun, bu tasarımların o kadar istikrarlı olmamasıydı. Değişen gereksinimlerimiz vardı ve bazen arayüzlerin kendilerinin de değişmesi gerekiyordu ve 200 alt tip tarafından uygulanan soyut bir arayüzü değiştirmek istediğinizde, bu oldukça maliyetli bir değişim. Aralarında bu tür tasarım değişikliklerinin maliyetlerini düşüren soyut temel sınıfları kullanarak azaltmaya başladık, ancak yine de pahalılardı.

Bu yüzden alternatif olarak, oyun endüstrisinde yaygın olarak kullanılan varlık-bileşen sistemi mimarisini keşfetmeye başladım. Bu şekilde olması için her şeyi değiştirdi:

görüntü tanımını buraya girin

Ve vay! Bu, bakım açısından böyle bir fark oldu. Bağımlılıklar artık soyutlamalara değil , verilere (bileşenlere) doğru akıyordu . Ve benim durumumda, en azından, değişen gereksinimlere rağmen, tasarım açısından en doğru olanı elde etmek için çok daha kararlı ve daha kolaydı (yine de aynı verilerle yapabileceklerimiz sürekli değişen gereksinimlerle değişiyor olsa da).

Ayrıca bir ECS'deki varlıkların miras yerine kompozisyon kullanması nedeniyle aslında işlevsellik içermeleri gerekmez. Bunlar sadece analog "bileşen kabı" dır. Böylece, bir hareket ara yüzünü uygulayan analog 200 alt- tip, bir hareket bileşenini (hareketle ilişkili verilerden başka bir şey olmayan ) saklayan 200 varlık örneğine (ayrı kodlu ayrı tipler değil) dönüşür . A artık ayrı bir sınıf / alt tip değildir. Hiç bir sınıf değil. Bu, sadece uzayda (hareket) bulunduğu yerle ilgili bazı bileşenleri (verileri) ve nokta ışıklarının belirli özelliklerini birleştiren bir varlık örneğidir. Onlarla ilişkilendirilen tek işlev,PointLightRenderSystemSahnenin nasıl oluşturulacağını belirlemek için sahnedeki hafif bileşenleri arar.

ECS yaklaşımı altındaki değişen gereksinimlerle, çoğu zaman yalnızca bu veriler üzerinde çalışan bir veya iki sistemi değiştirmeye ya da sadece yeni bir sistemi uygulamaya koymaya ya da yeni verilere ihtiyaç duyulduğunda yeni bir bileşen sunmaya ihtiyaç duyuluyordu.

Bu yüzden, en azından benim alanım için ve herkes için olmadığından neredeyse eminim, bu durum işleri çok daha kolaylaştırdı çünkü bağımlılıklar dengeye doğru akıyordu (sık sık değişmesi gerekmeyen şeyler). COM mimarisinde, bağımlılıklar soyutlamalara doğru bir şekilde akarken, durum böyle değildi. Benim durumumda, önünüzdeki hareket için hangi verilerin gerekli olduğunu bulmaktan daha kolaydır, bununla birlikte yapabileceğiniz tüm olası şeyler yerine, çoğu zaman yeni gereksinimler ortaya çıktıkça aylar veya yıllar içinde biraz değişir.

görüntü tanımını buraya girin

OID'de, SOLID ilkelerinin bir kısmının veya tamamının, kodu temizlemek için kendilerini ödünç vermediği durumlar var mı?

Pekala, temiz kod Bazı insanlar temiz kodu SOLID ile eşitleştiği için söyleyemem, ancak kesinlikle ECS'nin yaptığı gibi işlevsellikten verileri ayırmanın ve bağımlılıkları soyutlamalardan veriye yönlendirmenin işleri kesinlikle çok daha kolay hale getirebileceği bazı durumlar vardır. Açıkça birleştirme nedenlerinden dolayı, veriler soyutlamalardan çok daha kararlı olacaksa değiştirin. Elbette verilere olan bağımlılıklar değişmezlerin korunmasını zorlaştırabilir, ancak ECS verilen herhangi bir bileşene erişen sistem sayısını en aza indiren sistem organizasyonu ile bunu en aza indirgeme eğilimindedir.

DIP'nin önerdiği gibi bağımlılıkların soyutlamaya doğru akması gerekmez; Bağımlılıklar gelecekteki değişikliklere ihtiyaç duyması muhtemel olmayan şeylere doğru akmalıdır. Bu, her durumda soyutlamalar olabilir veya olmayabilir (kesinlikle benim değildi).

  1. Evet, kısmen SOLID ile çatışan OOP tasarım ilkeleri mevcut
  2. Evet, tamamen SOLID ile çelişen OOP tasarım ilkeleri mevcut.

ECS'nin gerçekten bir OOP tadı olup olmadığından emin değilim. Bazı insanlar bunu böyle tanımlamaktadır, fakat ben onu birleştirme özelliklerinden ve verilerin (bileşenlerin) işlevsellikten (sistemlerden) ve veri kapsülleme eksikliğinden ayrılmasından çok farklı görüyorum. Bir OOP şekli olarak kabul edilirse, bunun SOLID (en azından en katı SRP, açık / kapalı, liskov ikame ve DIP fikirleri) ile çatışmakta olduğunu düşünürdüm. Ancak umarım bu, en azından insanların kendilerini daha tanınabilir bir OOP bağlamında yorumlayacağı gibi, SOLID'in en temel yönlerinin bu kadar uygulanabilir olmayabileceği bir durum ve alanın makul bir örneğidir.

Ufacık Sınıflar

Arkadaşlarımın sürprizine göre, birçok küçük sınıf ve birkaç soyutlama katmanı içeren oyunlarımdan birinin mimarisini açıklıyordum. Bunun, her şeye Tek Sorumluluk vermeye ve aynı zamanda bileşenler arasındaki eşleşmeyi gevşetmeye odaklanmamın sonucu olduğunu savundum.

ECS meydan okudu ve görüşlerimi çok değiştirdi. Sizin gibi, sürdürülebilirlik fikrinin mümkün olan şeyler için en basit uygulamaya sahip olduğunu düşünürdüm, bu da birçok şeyi ima eder, ve ayrıca, birbirine bağımlı olan birçok şey (karşılıklı bağımlılıklar soyutlamalar arasında olsa bile). En basit, basit uygulamayı görmek ve sadece bir sınıfı veya işlevi yakınlaştırıyorsanız, en basit, basit uygulamayı görmek istiyorsanız ve bir tanesini göremezsek, onu yeniden düzenleyebilir ve hatta daha da ayrıştırabilirsiniz. Ancak, sonuç olarak dış dünyayla olan biteni kaçırmak kolay olabilir, çünkü göreceli olarak karmaşık bir şeyi 2 veya daha fazla şeye ayırdığınızda, bu 2 veya daha fazla şey kaçınılmaz olarak birbirleriyle etkileşime girmelidir * (aşağıya bakınız) ya da dışarıdaki bir şeyin hepsi ile etkileşime girmesi gerekir.

Bugünlerde, bir şeyin basitliği ile ne kadar şey olduğu ve ne kadar etkileşimin gerekli olduğu arasında bir dengeleme hareketi olduğunu görüyorum. Bir ECS'deki sistemler, PhysicsSystemya RenderSystemda ya da gibi veriler üzerinde çalışmak için önemsiz olmayan uygulamalarla oldukça ağır olma eğilimindedir GuiLayoutSystem. Bununla birlikte, karmaşık bir ürünün çok azına ihtiyaç duyması, geri adım atmayı kolaylaştırma ve tüm kod tabanının genel davranışı hakkında neden olma eğilimindedir. Orada, daha az sayıda, daha zorlu sınıfların (hala tartışmalı bir tekil sorumluluk üstlenerek) yanlarına yaslanmanın kötü bir fikir olmadığını düşünebilecek bir şey var. sistem.

Etkileşimler

Diyelim ki "birleşme" yerine "etkileşimler" diyorum (etkileşimleri azaltmak her ikisini de azaltmayı ima ediyor), çünkü iki somut nesneyi ayırmak için soyutlamalar kullanabilirsiniz, ancak yine de birbirleriyle konuşurlar. Bu dolaylı iletişim sürecinde hala yan etkilere neden olabilirler. Sıklıkla bir sistemin doğruluğu hakkında akıl yürütme yeteneğimin, bu "etkileşimlerle" "eşleşme" den daha fazla olduğunu düşünüyorum. Etkileşimin en aza indirilmesi, benim için her şeyden kuşbakışı bakış açısına bakmamı kolaylaştırır. Bu, birbirleriyle hiç konuşmayan şeyler anlamına gelir ve bu anlamda ECS aynı zamanda “etkileşimleri” en aza indirgeme eğilimindedir ve en azından en azından sahip olduğum en az şeyle eşleşmeyi değil

Bu, en azından kısmen ben ve kişisel zayıf yönlerim olabileceğini söyledi. Muazzam ölçekte sistemler yaratmam için en büyük engeli buldum ve yine de onlar için güvenle nedenlerim var, aralarında gezinebilirim ve öngörülebilir bir şekilde herhangi bir yerde istenen herhangi bir potansiyel değişikliği yapabileceğimi hissediyorum, devlet ve kaynak yönetimi ile birlikte yan etkiler. Tamamen kendi başıma yazdığım kod için bile, on binlerce LOC'den yüz binlerce LOC'dan milyonlarca LOC'ye geçerken ortaya çıkmaya başlayan en büyük engel bu. Bir şey beni her şeyden önce sürünmeye yavaşlatacaksa, bu durum uygulama durumu, veriler ve yan etkiler açısından neler olup bittiğini artık anlayamayacağım anlamına geliyor. O' Sistem aklımdaki sebep kabiliyetini aşarsa büyürse, değişimin tüm etkilerini anlayamama kadar beni yavaşlatan bir değişiklik yapmak için gereken robotik zaman değil. Ve etkileşimleri azaltmak, benim için, kişisel olarak bunlardan çok etkilenmeden, çok daha fazla özellik ile ürünün daha fazla büyümesine izin vermenin en etkili yoluydu, çünkü etkileşimleri en aza indirgemek mümkün olan yer sayısını azaltır. uygulama durumunu bile değiştirebilir ve önemli ölçüde yan etkilere neden olabilir.

Böyle bir şeyi döndürebilir (şemadaki her şeyin işlevselliğe sahip olduğu ve açıkçası gerçek dünya senaryosunun birçok kez nesneye sahip olacağı ve bu bir eşleştirme olarak değil, bir eşleştirme değil, bir "etkileşim" şemasıdır. biri arasında soyutlamalar olurdu):

görüntü tanımını buraya girin

... bunun için sadece sistemlerin işlevselliği olduğu yerler (mavi bileşenler şimdi sadece veridir ve şimdi bu bir bağlantı şemasıdır):

görüntü tanımını buraya girin

Bunların hepsinde ortaya çıkan ve belki de bu faydaların bazılarını SOLID ile daha uyumlu bir OOP bağlamında çerçevelemenin bir yolu var, ama henüz tasarımları ve kelimeleri henüz bulamadım. Ben terminoloji ben doğrudan OOP ile ilgili tüm etrafa atmak için kullanılan beri zor. Buradaki insanların cevaplarını okuyarak ve kendime göre formüle etmek için elimden gelenin en iyisini yapmaya çalışıyorum ama ECS'nin doğası hakkında parmağımı tam olarak yerleştiremediğim için çok ilginç şeyler var. onu kullanmayan mimarilere bile daha geniş çapta uygulanabilir. Ayrıca, bu cevabın ECS'nin bir promosyonu olarak çıkmadığını da umarım! Bir ECS tasarlamak gerçekten düşüncelerimi ciddi bir şekilde değiştirdiği için çok ilginç buluyorum.


Etkileşim ve eşleşme arasındaki farkı seviyorum. Her ne kadar ilk etkileşim diyagramınız karışık olsa da. Bu düzlemsel bir grafiktir, bu yüzden okları geçmeye gerek yoktur.
D Drmmr

2

KATI ilkeler iyidir, ancak çatışmalarda KISS ve YAGNI önceliklidir. SOLID'in amacı karmaşıklığı yönetmektir, ancak SOLID'in kendisi uygulanması kodu daha karmaşık hale getirirse, amacı ortadan kaldırır. Örnek vermek gerekirse, sadece birkaç sınıfa sahip küçük bir programınız varsa, DI, arayüz ayrımı vb. Uygulamak programın genel karmaşıklığını çok iyi artırabilir.

Açık / kapalı prensibi özellikle tartışmalıdır. Temel olarak, bir alt sınıf veya aynı arabirimin ayrı bir uygulamasını oluşturarak bir sınıfa özellikler eklemeniz gerektiğini, ancak orijinal sınıfı dokunmadan bıraktığınızı söylüyor. Eşgüdümlü olmayan müşteriler tarafından kullanılan bir kütüphane veya hizmeti sürdürüyorsanız, bu, müşteriden çıkacak olan davranışı bozmak istemediğiniz için mantıklıdır. Ancak, yalnızca kendi uygulamanızda kullanılan bir sınıfı değiştiriyorsanız, sınıfı kolayca değiştirmek genellikle daha kolay ve temiz olacaktır.


OCP hakkındaki tartışmanız, bir sınıfın davranışını genişletme olasılığını göz ardı eder (örneğin, sınıf tarafından kullanılan bir algoritmanın değiştirilmesine izin veren bir strateji nesnesinin kullanılması); .
Jules

1
KISS ve YAGNI her zaman önceliğe sahipse, hala 1 ve 0'larda kod yazıyor olmalısınız. Montajcılar sadece yanlış gidebilecek başka bir şeydir. Hiçbir KISS ve YAGNI tasarım çalışmalarının maliyetinin ikisini göstermez. Bu maliyet her zaman herhangi bir tasarım çalışmasının yararına karşı dengelenmelidir. SOLID, bazı durumlarda masrafları karşıladığı için avantajlara sahiptir. Çizgiyi ne zaman geçtiğini söylemenin basit bir yolu yok.
candied_orange

@CandiedOrange: Makine kodunun yüksek seviyeli bir dilde koddan daha basit olduğunu kabul etmiyorum. Makine kodu, soyutlamanın olmamasından dolayı birçok kazayla karmaşıklık içerdiğinden sona erer, bu nedenle kesinlikle makine kodunda tipik bir uygulama yazmaya karar vermek KISS değildir.
JacquesB

@Jules: Evet kompozisyon tercih edilir, ancak yine de orijinal sınıfı kompozisyonun kişiselleştirmek için kullanılabileceği şekilde tasarlamanızı gerektirir, bu nedenle gelecekte hangi özelliklerin gelecekte kişiselleştirilmesi gerektiği ve hangi özelliklerin özelleştirilmesi gerektiği konusunda varsayımlarda bulunmanız gerekir. özelleştirilebilir değil. Bazı durumlarda bunu yapmak zorunludur (örneğin dağıtım için bir kütüphane yazıyorsunuz) ancak bunun bir maliyeti var, bu nedenle SOLID'i takip etmek her zaman en uygun değil .
JacquesB

1
@ JacquesB - doğru. OCP ise özünde YAGNI'ye karşıdır; ancak bunu başarmaya devam ederseniz, daha sonra iyileştirmeyi sağlamak için uzatma noktalarında tasarım yapmanızı gerektirir. İki ideal arasında uygun bir denge noktası bulmak ... zordur.
Jules

1

Tecrübelerime göre:-

Büyük sınıflar büyüdükçe katlanarak bakımı daha zordur.

Küçük sınıfların bakımı daha kolaydır ve küçük sınıf koleksiyonunu sürdürmenin zorluğu sınıf sayısına göre aritmetik olarak artar.

Bazen büyük sınıflar kaçınılmazdır, büyük bir problem bazen büyük bir sınıfa ihtiyaç duyar, ancak okuması ve anlaşılması çok daha zordur. İyi adlandırılmış daha küçük sınıflar için, yalnızca ad, sınıfla ilgili çok özel bir sorun olmadıkça, koda bakmanıza bile gerek duymadığınızı anlamak için yeterli olabilir.


0

Bir katı 'S' ile (eski moda olabilir) arasında bir nesnenin kendisinin tüm bilgisine sahip olması için gereken çizgiyi çizmeyi her zaman zor buluyorum.

15 yıl önce, her şeyi içeren sınıflara sahip olmak için kutsal kâselerine sahip olan Deplhi geliştiricileri ile çalıştım. Yani bir ipotek için sigortalar, ödemeler, gelir ve krediler ve vergi bilgileri ekleyebilir ve vergi ödemesi, vergi kesintisi hesaplayabilir ve kendini seri hale getirebilir, kendini diske koyabilir vb.

Ve şimdi aynı nesneyi, çok daha kolay ve daha iyi bir şekilde test edilebilecek olma avantajına sahip olan ve tüm işletme modeline iyi bir genel bakış göstermeyen avantajlı çok ve daha küçük sınıflarda tasarladık.

Ve evet, nesnelerinizi veritabanına bağlamak istemediğinizi biliyorum, ancak bunu çözmek için büyük ipotek sınıfında bir havuz enjekte edebilirsiniz.

Bunun yanında, sadece küçük bir şey yapan sınıflar için iyi adlar bulmak her zaman kolay değildir.

Bu yüzden 'S'nin daima iyi bir fikir olduğuna emin değilim.

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.