2013-01-10 28 views
5

Yardımınıza ihtiyacım var. Bir RPG oyununda bir yetenek gerçekleştirilebilmeden önce çeşitli koşulları kontrol edebilen bir betik düzenleme ortasındayım. Bütün bu yetenekler, hepsi soyut bir sınıfa (Yetenek) ait olan, başka bir soyut sınıftan (Menzilli yetenek, İyileştirme yeteneği, DOT yeteneği) türetilmiş bireysel sınıflarda (Ateş topu, Heal, Poison) bulunmaktadır. Ben yeteneklerini her türlü alabilir tek bir işlev çağrısı oluşturmak çalışıyorumC#, Unity - Birden çok farklı nesne alan tekli işlev

void condition(Fireball f){//test}; 
void condition(Heal f){//test}; 
void condition(Poison f){//test}; 

: Birden fonksiyonları yaratmaktan kaçınmak için her yeteneğini işlemek amacıyla

.

void condition(Ability f){//test} 

Şimdiye kadar bir Fireball nesnesi oluşturmayı ve onu işleve iletmeyi başardım.

Fireball _fire = new FireBall(); 
condition(_fire); 

void condition(Ability f){//test} 

Buradan ben Yeteneği sınıfında başlatıldı tüm kamu değişkenleri erişebilir, ama türetilmiş sınıfları başlatıldı kamu değişkenler (Menzilli yetenek, Şifa yeteneği, DOT yetenek) erişemez.

Bana bir şeyi unutmadan mı, yoksa yanlış bir bakış açısıyla mı bakıyorum? (Miras ve soyut sınıfları kullanmakta büyük değilim.)

+0

Klasik OOP polimorfizm/kalıtım sorunu :) Kapsülleme ve konfor kullanımını koruyacak bir çözüm düşünmek zor ve eğlenceli. +1. – dreamzor

+0

Bunun Objective C ile ne ilgisi var? –

+0

Üzgünüm, sanırım yanlış etiketledim. –

cevap

8

Durum işlevinin ne yaptığını daha fazla ayrıntı bilmeden, iki seçeneğiniz vardır.

One, sen

if (f.GetType() == typeof(FireBall)) 
{ 
    fireBall = (FireBall)f; 
    fireBall.FireTheFireBall(); 
} 
else if (f.GetType() == typeof(Heal)) 
... 

Veya böyle bir şey yapabileceği tüm türetilmiş sınıfları aşırı gerekmektedir soyut bir etkinleştirme yöntemi, olabilir sizin yeteneği: Sonra

class Fireball 
{ 
    public override void Activate() 
    { 
     //do fireball specific things 
     this.FireTheFireBall(); 
    } 

    public void FireTheFireBall() {...}  
} 

class Heal 
{ 
    public override void Activate() 
    { 
     //do healing specific things 
     this.ApplyTheBandage(); 
    } 
    ... 
} 

abstract class Ability 
{ 
    public abstract void Activate(); 
} 

void condition(Ability f){ 
    f.Activate(); //runs the version of Activate of the derived class 
} 

çalışır herhangi bir şey Bir Yeteneğe sahip olmak bazıAbility.Activate() öğesini çağırır ve türetilmiş sınıfın sağladığı uygulama gerçekleştirilir.

Ayrıca soyut sınıflar gibi olan arayüzler üzerinde de çalışmalısınız. Arayüzlerin faydası, bunlardan birçoğunu uygulayabilmenizdir, oysa bunlardan sadece bir temel soyut sınıftan miras almanız sınırlıdır. Dönüş ve Çekme işlevlerine sahip bir IKnob arabirimini düşünün. IKnob, bir Kapı sınıfı, Turn'i uygulayan ve bir tuzağı aktive eden bir TrappedDoor sınıfı uygulayan bir Çekmece sınıfınız olabilir. Bir oyuncu bir kapıya doğru yürür, ve üzerinde kullan düğmesini vurur ve siz açın (IKnob topuzu)

void Open(IKnob knob) 
{ 
    knob.Turn(); 
    knob.Pull(); 
} 

class TrappedDoor:IKnob,IMaterial,ISomethingElse,IHaveTheseOtherCapabilitiesAsWell 
{ 
    private bool TrapAlreadySprung{get;set;} 
    //more complex properties would allow traps to be attached either to the knob, or the door, such that in one case turning the knob activates the trap, and in the other, Pull activates the trap 
    public Turn() { 
    if(! TrapAlreadySprung) 
    { 
     MessageBox("You hit your head, now you're dead"); 
    } 
    } 
} 

şey bir arayüze sahip olmadığını kontrol etmenin yollarını var açık işleve nesneyi geçmesi, eğer öyleyse Bazı oyuncu bir öğeye doğru yürür ve onunla konuşmaya çalışır. Nesnenin ICanTalk arabirimine sahip olup olmadığını kontrol edebilirsiniz, eğer o zaman object.GetReply ("Merhaba") çağrılırsa ve nesne yanıt verebilir. Yani arzu ederseniz kapıları ve kayaları konuşabilirsiniz. ICanTalk arabirim yöntemleri ile çalışan şeylere/yanıt veren şeylere cevap veren tüm kodlarınızı alırsınız ve daha sonra diğer sınıflar ICanTalk'ı uygulayabilir ve her biri nasıl yanıt verileceğine karar verir. Bu kavram "endişelerin ayrılması" olarak bilinir ve daha çok yeniden kullanılabilir kod oluşturmanıza yardımcı olur.

Önemli olan, yalnızca bu arabirimle çalışan bir kod, bir algoritma, işlev vb. Parçasını yazabilmeniz ve bu kodun arabirimle çalışmasını sağladığınızda, o arabirimi Herhangi bir sınıf, ve bu sınıf, önceden varolan kodu kaldırabilir.

I.I.I.e. condition işleviniz, bir IAbility arabiriminde çekildiyse, bu kod çalıştıktan sonra, o zaman IAbility uygulayan her sınıf, koşul işlevine iletilebilir. Durum işlevi, ne gerekiyorsa yapılmakla yükümlüdür ve IAbility'yi uygulayan sınıf, uyguladığı yöntemlerin içine özgü olan her şeye sahiptir.

Elbette, soyut sınıfı veya arabirimi uygulayan sınıflar, gereken yöntemleri uygulamalıdır, bu nedenle bazen kodu kopyaladığınız gibi hissedebilirsiniz. Örneğin, TrappedDoor ve Door gibi benzer sınıflarınız varsa, bir TrappedDoor, tuzak ayarlanmamışsa/zaten yayılmışsa, normal bir Kapı gibi davranabilir. Yani bu durumda ya Kapıdan miras alınabilir ya da özel bir Kapı özelliğine ("kompozisyon" olarak bilinir) sahip olabilirsiniz. Tuzak zaten yayılmışsa, temel Kapı sınıfına veya özel Kapı özelliğine çağrı yapabilir ve tuzak aktif değilse, normal bir kapının varsayılan davranışını yeniden kullanabilmeniz için .Turn'u çağırabilirsiniz.

Test if object implements interface

Kişisel çoğunlukla yerine kalıtım, arabirim ve bileşimin kullanılması. Bu kalıtsallık korkunç değil, miras hiyerarşileri hızla çok karmaşık hale gelebilir.

+0

Cevabınız için teşekkür ederiz. İkinci önerinin nasıl çalıştığından emin değilim, ama aslında ilk önerinin işe yarayabileceğini düşünüyorum. En kısa zamanda inceleyeceğim ve geri bildireceğim :) –

+0

@Marc İkinci örneği genişletmek için güncellendi. – AaronLS

+1

İkinci örnek, şüphelendiğim çok daha mantıklı bir fikre benziyor ... :) –

İlgili konular