2012-01-22 25 views
5

Projemde bir grup dersim var (aşağıdaki strateji modeli). Ana işlevde, sunucudan bir enum değeri alıyorum ve temel sınıf türünde bir nesne oluşturduğuma göre.Enum kullanarak sınıf türünü nasıl çözülür

Bunu başarmak için anahtar/vaka bildirimini kullanıyorum. Açık/Kapalı ilkesinin, yeni bir sınıf eklendiğinde yeni bir durum ifadesi eklemeye yönelik bir işlev açmasına izin vermediğini bir yerde okudum.

Activator.CreateInstance() kullanmayı düşünüyorum. Bunun bir dezavantajı var mı?

Numara türünden nesne oluşturmanın başka bir yolu var mı?

Bunu bir işleve enum türünden bir Dictionary kullanabilirsiniz tam teşekküllü Strateji desen

abstract public class Mammal 
{ 
    public abstract void MakeSound() 
} 

class Cat:Mammal 
{  
    public override void MakeSound() 
    { 
     Console.WriteLine("Meow");   
    }  
} 

class Dog:Mammal 
{ 

    public override void MakeSound() 
    { 
     Console.WriteLine("Bow");   
    }  
} 

Main() 
{ 

    MammalTypes mammalType = RecieveValueFromServer(); 
    Mammal mammalBase 
    switch(mammalType) // need to make this dynamic depending upon Enum type 
    { 
     case MammalTypes.Cat:mammalBase = new Cat() 
          break; 
     case MammalTypes.Dog:mammalBase = new Dog() 
          break;    
    } 

    mammalBase.MakeSound() 
} 
+2

** NOT ** Nesne Yönelimli. Temel sınıf, türetilmiş sınıfların farkında olmamalıdır. – gdoron

+1

Yaptıklarınızı görselleştirmek zor. Lütfen sorunuza yazdığınız kodu ekleyin. – Abbas

cevap

1

olmadığı halde aşağıdaki örneği ekleme. işlevleri strateji nesnesi oluşturur:

public delegate Strategy StrategyFactory(); 
var strategyFactories = new Dictionary<MyEnum, StrategyFactory>(); 

numaralandırma değerlerine dayanarak nesneleri oluşturmak için kullanılan bu sözlüğü:

var newStategy = strategyFactories[myEnumValue](); 

fonksiyonları nasılsa sözlüğe eklenmesi gerekir fabrikası. Bunun için kayıt (ve belki de kayıt dışı) yöntemleri ortaya çıkarabilirsiniz.

0

Sen sıralama değeri temsil ettiğini Tipi götüren bir Özellik oluşturmak ve böylece gibi enum alanına uygulamak olabilir:

enum MyEnum { 
    [Creates(typeof(FooStrategy))] 
    Foo, 
    [Creates(typeof(BarStrategy))] 
    Bar, 
    // etc. 
} 

[AttributeUsage(AttributeTargets.Field, Inherited=false, AllowMultiple=false)] 
sealed class CreatesAttribute : Attribute { 
    public Type TypeToCreate { get; private set; } 
    public CreatesAttribute(Type typeToCreate) { 
     TypeToCreate = typeToCreate; 
    } 

    public static IDictionary<T, Func<U>> GenerateLookup<T,U>() { 
     var query = from field in typeof(T).GetFields() 
        let creates = field.GetCustomAttriubtes(typeof(CreatesAttribute), false) as CreatesAttribute[] 
        let method = CreationMethod(typeof(U)) // create your type here 
        let key = (T)field.GetValue(null) 
        select new { Key = key, Method = method }; 
     return q.ToDictionary(item => item.Key, item => item.Method); 
    } 
} 

kısım size kalmış sol Eğer bir örneğini oluşturmak istiyorum nasıl edilir Senin sınıfın. Hepsi aynı kurucuya sahipse, bu yöntem Type.GetConstructor(Type[]) numaralı telefonu arayabilir ve numaranızı ConstructorInfo örneğiyle arayabilir veya bir IoC kabı kullanabilir ve türünden bir örneği çözebilir, farklı kurucular hakkında çok fazla endişelenmenize gerek yoktur. parametreleri.

public static class MyEnumExtensions { 
    static readonly IDictionary<MyEnumType, MyBaseStrategyType> lookup = 
     CreatesAttribute.GenerateLookup<MyEnumType, MyBaseStrategyType>(); 

    public static MyBaseStrategyType CreateInstance(this MyEnumType key) { 
      return lookup[key](/* pass any common constructor values */); 
    } 
} 

Son olarak şöyle çağırır:

Sonra numaralama üzerinde uzatma yöntemleri için statik bir sınıf oluşturabilir

var myEnum = MyEnumType.Foo; 
var strategy = myEnum.CreateInstance(); 
// use your strategy 

Bu açık ihlal sizi tutmalı/kapalı İlke ve istediğiniz kadar çok sınıf eklemenize izin verin ve Enum değerini, enum değerinden doğrudan stratejinin bir örneğini oluşturacak kadar genel olarak yapılabilecek Enum'u değiştirin.

4

aşağıdaki olabilir doğrudur OCP'yi başarılması için bir yöntem:

abstract public class Mammal 
{ 
    public abstract void MakeSound(); 

    public abstract bool Is(MammalTypes mammalType); 
} 
:

Memeli her somut alt türü zorlamak için soyut bir yöntem Is tanımlayın enum belirli bir değeri için uygun olup olmadığını belirlemek için Bu yapılırken

class Cat : Mammal 
{ 
    // other specific members 

    public override bool Is(MammalTypes mammalType) 
    { 
     return mammalType == MammalTypes.Cat; 
    } 
} 

class Dog : Mammal 
{ 
    // other specific members 

    public override bool Is(MammalTypes mammalType) 
    { 
     return mammalType == MammalTypes.Dog; 
    } 
} 

, artık MammalF oluşturabilirsiniz: gibi alt sınıflar İş'in

uygulamaları olmazdı

public class MammalFactory 
{ 
    private readonly IEnumerable<Type> _mammalTypes; 

    public MammalFactory() 
    { 
     var currentAssembly = Assembly.GetExecutingAssembly(); 

     _mammalTypes = currentAssembly.GetTypes() 
      .Where(t => typeof(Mammal).IsAssignableFrom(t) && !t.IsAbstract); 
    } 

    public Mammal Create(MammalTypes mammalType) 
    { 
     return _mammalTypes 
      .Select(type => CreateSpecific(type, mammalType)) 
      .First(mammal => mammal != null); 
    } 

    public Mammal CreateSpecific(Type type, MammalTypes mammalEnumType) 
    { 
     var mammalInstance = (Mammal)Activator.CreateInstance(type); 

     return mammalInstance.Is(mammalEnumType) ? mammalInstance : null; 
    } 
} 

nihai kullanım aşağıdaki gibi görünecektir:

var mammalFactory = new MammalFactory(); 

var guessWhatMammal = mammalFactory.Create(MammalTypes.Cat); 
bir eşleşme bulursa mevcut sınıflar ve üzerinden bir memeli sıralama değeri taramaları verildiğinde, bu sınıfta bir örneğini döndürür abrika sınıf

Bu, OCP'ye tam olarak uygundur. Uygulama için otomatik olarak kablolu ve kullanıma hazır olması için sadece yeni bir Mammal sınıfı oluşturulmalıdır.

bu yaklaşımla bazı sorunlar vardır (gerek enum kendisi hariç, uygulamada başka bir şey değiştirmek için):

  • sadece memeli türleri için şu anda yürütülen montaj tarar
  • sahip olduğu Memeli o tip bu konular ele alınabilir iken

uygun olup olmadığını test etmek için gereken her zaman bir örneğini oluşturmak için, hala bırakılır: karmaşıklığı. biz kod miktarı otomatik kablolama

ben sonuca düşünüyorum projeye yeni insanlar için kafa karıştırıcı olabilir

  • gerekli iki katına çıkardık

    • çünkü:

      Bu

      karmaşıktır şudur: tasarım kalıpları katı kural değildir. Belirli bir tasarıma uymak için bir şey yapmaya değmez. Bunun yerine, pragmatik olmalı ve desen uyumu ile kullanışlılık/basitlik/okunabilirlik arasında mükemmel bir denge bulmalıyız. Bu, çözmeyi denediğimiz soruna büyük ölçüde bağlıdır ve birçok durumda, soruda sunduğunuz switch beyanı olabilir.