“Boş” Özet / Dersleriniz Olabilir mi?


10

Tabii ki yapabilirsiniz, sadece böyle bir şekilde tasarım yapmanın mantıklı olup olmadığını merak ediyorum.

Koparma klonu yapıyorum ve sınıf tasarımı yapıyordum. C ++ 'da öğrendiklerimi uygulamak için gerekmeme rağmen kalıtım kullanmak istedim. Sınıf tasarımını düşünüyordum ve şöyle bir şey buldum:

GameObject -> temel sınıf (x ve y ofsetleri gibi veri üyelerinden ve bir SDL_Surface *

MovableObject: GameObject -> soyut sınıf + türetilmiş GameObject sınıfından oluşur (bir yöntem void move () = 0;)

NonMovableObject: GameObject -> boş sınıf ... yapıcı ve yıkıcı dışında hiçbir yöntem veya veri üyesi yok (en azından şimdilik?).

Daha sonra Tileset: NonMovableObject gibi NonMovableObject'ten bir sınıf türetmeyi planlıyordum. Sadece "boş" soyut sınıflar mı yoksa sadece boş sınıflar mı kullanıldığını merak ediyordum ... Bunu yaptığım gibi, sadece sınıflandırma uğruna NonMovableObject sınıfını oluşturuyorum.

Sadece bir koparma klonu yapmak için şeyleri düşünmeyi biliyorum, ama odaklandığım şey oyuna daha az, miras kullanmak ve bir çeşit oyun çerçevesi tasarlamak.

Yanıtlar:


2

C ++ 'da Çoklu Kalıtım var, bu yüzden bu boş sınıflara sahip olmanın hiçbir faydası yoktur. Daha sonra Ball'un GameObject ve MovableObject'ten miras almasını istiyorsanız (örneğin, örneğin, GameObjects dizisini tutmak ve hepsini hareket ettirmek için saniyenin her saniyesinde bir Tick yöntemi çağırmak istiyorsunuz), bunu yapmak yeterince kolay.

Ancak, bu durumda, kişisel olarak aksiyomun " kompozisyonu kalıtım yerine tercih etmeyi (kapsülleme) tercih ettiğini" hatırlamanızı ve Devlet modeline bakmanızı öneririm . Her nesnenin hareket durumunu daha sonra olmasını istiyorsanız, GameObject öğesine iletin. Örneğin: Top için DiagonalBouncingMovementState, raket için HoriazontalControlledMovementState, bir tuğla için NoMovementState.

1) Bu , eğer seçerseniz (yine tavsiye ederim) birim testleri yazmanızı kolaylaştıracaktır - çünkü GameObject'i ve eyaletlerinizin her birini bağımsız olarak test edebilirsiniz.

2) Tuğlalardan düşen jetonlarınız olduğunu söyleyin, ancak onlardan birini çapraz olarak hareket edecek şekilde değiştirmek istediğinizi söyleyin - sınıf kalıtımının bazı karmaşık hiyerarşisi etrafında kaydırmak yerine, sadece kendisine geçirilen sabit kodlu hareket durumunu değiştirebilirsiniz .

3) En önemlisi: Topun ve / veya raketin bu jetonlara göre nasıl hareket ettiğini oyun içinde değiştirmeye başlamak istediğinizde , hareket durumunu değiştirmeye devam edersiniz (DiagonalMovementState, DiagonalWithGravityMovementState olur).

Şimdi, bunların hiçbiri, mirasın neden kapsüllenmeyi tercih ettiğimizi göstermek için mirasın her zaman kötü olduğunu öne sürmüyordu. Yine de her nesne türünü GameObject öğesinden türetmek ve bu sınıfların ilk Hareket Durumlarını anlamalarını isteyebilirsiniz. Neredeyse kesinlikle hareket durumlarınızın her birini soyut bir MovementState sınıfından türetmek isteyeceksiniz, çünkü C ++ arayüzleri yoktur.

$ 0.02


8

Java'da, "boş" arabirimler işaretçi olarak kullanılır (örn. Serializable), çünkü çalışma zamanında nesneler bu arabirimi "uygulayıp uygulamadıklarına" bakılmaksızın kontrol edilebilir; ama C ++ 'da bana çok anlamsız geliyor.

IMO, dil özellikleri araç olarak düşünülmeli, yükümlülüklere değil belirli hedeflere ulaşmanıza yardımcı olacak bir şey. Sadece çünkü edebilirsiniz sen gelmez bir özelliği kullanmak zorunda . Anlamsız kalıtım bir programı daha iyi yapmaz.


3

Bunu fazla düşünmüyorsunuz; düşünüyorsun ve bu iyi.

Daha önce de belirtildiği gibi, sadece orada olduğu için bir dil özelliği kullanmayın. Dil öğrenme özelliği ödülleri iyi tasarımın anahtarıdır.

Sınıflandırma için temel sınıflar kullanılmamalıdır. Bu kontrol tipini etkileyebilir. Bu kötü bir fikir.

Nesnelerinizin sözleşmesini tanımlayan saf soyutlamalar yazmayı düşünün. Nesnelerinizin sözleşmesi dışa dönük arayüzdür. Genel arayüzü. Bu ne yapar.

Not: Bu anlamak önemlidir değil sahip olduğu hangi verilerin x, yama ne yapar move().

Tasarımınızda bir sınıfınız var GameObject. İşlevleri için değil, verileri için ona güveniyorsunuz. Bu hissediyor senin durumunda, ortak paylaşılan verileri gibi görünüyor paylaşım için miras kullanmayı verimli ve doğru xve y.

Bu kalıtımın doğru kullanımı değildir. Unutmayın, kalıtım muhtemelen sahip olabileceğiniz en sıkı bağlantı türüdür ve her zaman gevşek bağlantı için çaba göstermelisiniz.

Doğası gereği NonMovableObjecthareket etmiyor. Onun xve ykesinlikle ilan edilmelidir const. Doğası gereği MoveableObjecthareket etmek gerekiyor. Onun xve yolduğu gibi ilan edemez const. Dolayısıyla, bu aynı veri değildir ve paylaşılamaz.

Nesnelerinizin işlevselliğini veya sözleşmesini göz önünde bulundurun. Ne gerekir yapmak ? Doğru olsun, veriler gelecek. Her seferinde bir nesne üzerinde çalışın. Sırayla her biri için endişelen. İyi tasarımlarınızın yeniden kullanılabilir olduğunu göreceksiniz.

Belki de hiç yoktur NonMovableObject. GameObjectBaseBir move()yöntemi tanımlayan saf bir soyutlamaya ne dersiniz ? Sisteminiz GameObjectuygulayan move()örnekleri başlatır ve sistem yalnızca hareket etmesi gerekeni taşır.

Bu sadece başlangıç; bir tat. Tavşan deliği çok daha derine iniyor. Hiç kaşık yok.


Ne birbirlerinden ne MovableObjectde NonMovableObjectmiras kalmayacakları doğru olsa da , her ikisinin de bir yeri vardır; bu nedenle, her ikisi de örneğin bir canavarın amacını, bir nesnenin hareket edip edemeyeceğine bakılmaksızın bir nesneye doğru yönlendirmek isteyen kod tarafından tüketilmelidir.
supercat

2

Belirtilen C # gibi ammoQ uygulamalarına sahiptir, ancak C ++ 'ta NonMovableObject işaretlerinin bir listesine sahip olmak istiyorsanız tek uygulama olurdu.

Ama sonra nesneleri NonMoveableObject işaretçisi ile tahrip edeceğinizi hayal ediyorum, bu durumda sanal yıkıcılara ihtiyacınız olacak ve artık boş bir sınıf olmayacaktı. :)


Ben de bu davayı düşündüm, ama davranış sergileyen nesnelerin böyle bir listesi ile ne yapabilirdiniz? Büyük olasılıkla, bir şekilde gerçek türü bulur ve mevcut yöntemlere ve alanlara erişmek için bir döküm kullanırsınız - kesinlikle bir kod kokusu.
user281377

Evet bu iyi bir nokta.
tenpn

1

Bunu görebileceğiniz bir durum, güçlü bir şekilde oluşturulmuş bir koleksiyonun başka türlü heterojen türler içermesini istediğiniz yerdir. Ben, bu harika bir fikir demiyorum olabilir zayıf bir soyutlama veya kötü tasarıma işaret, ama olur. Bahsettiğiniz gibi, şeyleri kategorilere ayırmanın bir yoludur ve yararlı ve mükemmel bir şekilde geçerli olabilir.

Örneğin, Kediler ve Köpekler için bir koleksiyon istersiniz. Tasarımınızda ortak bir şeyleri olduğuna karar veriyorsunuz, bu yüzden temel bir Mamal sınıfına sahip olun ve koleksiyonunuzda bu türü kullanın (örn. Liste). Hepsi iyi. Daha sonra koleksiyonunuza biraz Kurbağa eklemek istediğinize karar veriyorsunuz, ancak bunlar memeliler değil, bu yüzden bunu yapmanın bir yolu Kurbağalar ve Memeliler alt sınıfını Hayvan yapmaktır, ancak belki Kurbağaların ve Memelilerin Hayvan boş kalır. Daha sonra koleksiyonunuzu Mamal yerine Animal ile yazıyorsunuz ve her şey yolunda.

Gerçek hayatta, er ya da geç boş bir temel sınıf oluştursam bile, bazı işlevselliklerin orada ortaya çıktığını, ancak kesinlikle var oldukları zamanların olduğunu görüyorum.


Ancak sorulması gereken bir soru şudur: eğer türlerin ortak bir yanı yoksa, neden aynı koleksiyonda tutuluyorlar? Koleksiyondaki tüm öğeler üzerinde yapabileceğiniz herhangi bir işlem yoktur, bu tür bir koleksiyona sahip olma amacını bozar. Şimdi mantığı basitleştirmek için her ikisine de eklemek isteyebileceğiniz bazı yapay işlemler olabilir - örneğin Ziyaretçi tasarım modelini uygulamak - bu noktada tekrar faydalı olabilir, ancak şimdi ortak bir şeyleri var ...
Jules
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.