2017-02-15 4 views
2

나는 각기 다른 성질을 가진 일련의 클래스를 가지고 있고 각각은 ID를 가지고있다 (인스턴스마다가 아닌 타입마다). 다음 감안할 때유형을 조건부로 정의하여 객체를 만드는 방법은 무엇입니까?

: 데이터를 읽을 때

public class TestEntity : EntityBase { 
    public override ushort ID { get; } = 1; 
    public override void something() { do_something(); } 
} 
public class OtherEntity : EntityBase { 
    public override ushort ID { get; } = 2; 
    public override void something() { something_else(); } 
} 

가 난 단지 가지고 ushort :

ushort EntityId = BitConverter.ToUInt16(data.GetRange(CURRENT_POSITION + TILE_ENTITY_ID_OFFSET, TILE_ENTITY_ID_LENGTH).ToArray().Reverse().ToArray(), 0); 

가 어떻게 그 가치를 기반으로하는 객체의 다른 유형을 만들 수 EntityId의 값을 사용합니까? if 또는 switch 문을 사용하는 것은 200 가지 이상의 유형이 있으므로 옵션이 아닙니다.

+1

https://en.wikipedia.org/wiki/Factory_method_pattern –

+0

@Matthew , 호출자는 그들이 원하는 것을 알고 있습니다. C# 코드 예제에서 볼 수 있듯이 공장에는 스위치가 필요합니다. – CodeCaster

+0

그건 공장을 짓는 한 가지 방법입니다. 다른 많은 것들이 있습니다. –

답변

3

가장 좋은 방법은 ID 속성이 포함 된 Attribute-Subclass를 정의한 다음 각 유형에 고유 한 ID를 제공하는 모든 유형에 속성을 주석으로 추가하는 것입니다.
Layter를 사용하면 주어진 속성 및 필터가 포함 된로드 된 유형을 속성의 ID 속성으로 수집하고 필터링 할 수 있습니다.
이 방법을 사용하면 나중에 소비 코드를 수정하지 않고도 하위 유형을 추가 할 수 있습니다.
구현이 같이 볼 수 있었다 : 나는 당신의 질문을 이해한다면 여기에 대해 이동하는 방법 중 하나입니다,

public sealed class MyCustomAttribute : Attribute 
{ 
    public ushort Id { get; set; } 

    public MyCustomAttribute(ushort id) 
    { 
     this.Id = id; 
    } 
} 

public class MyDemoConsumer 
{ 
    public void MyConsumingMethod(ushort requiredTypeId) 
    { 
     var requestedType = AppDomain 
      .CurrentDomain 
      .GetAssemblies() 
      .SelectMany(asm => asm.GetTypes()) 
      .Where(type => type.GetCustomAttributes(typeof(MyCustomAttribute), false).Any()) 
      .Select(type => new { Type = type, CustomId = type.GetCustomAttributes(typeof(MyCustomAttribute), false).Cast<MyCustomAttribute>().Single().Id }) 
      .Where(item => item.CustomId == requiredTypeId) 
      .Select(item => item.Type) 
      .SingleOrDefault(); 

     if (requestedType != null) 
     { 
      var result = Activator.CreateInstance(requestedType); 
     } 
    } 
} 
+1

200 가지 이상의 유형을 사용하면이 작업을 수행 할 수 있습니다. –

+0

@MichaelGunter 당신은 앞으로 처리해야하는 유형을 알 수 없습니다. –

+2

개인적으로 200 가지 이상의 유형이 이미 선언 된 경우 새로운 패턴을 발견하게됩니다. 그건 유지 보수의 악몽 같아. –

8

(많습니다). 공장 패턴

private static Dictionary<ushort, Type> TypeMap = new Dictionary<ushort, Type>() 
                { 
                 { 1, typeof(TestEntity) }, 
                 { 2, typeof(OtherEntity) } 
                }; 

private EntityBase CreateEntity(ushort id) 
{ 
    var type = TypeMap[id]; 
    return (EntityBase) Activator.CreateInstance(type); 
} 
+0

나는 똑같은 것을 썼습니다 ... 바로 당신의 빠른 손가락! +1 – TyCobb

+0

직장에서 천천히 하루. :) –

+0

@MichaelGunter 나에게서 아주 좋은 접근 (+1)! – Christos

3

...이 일을하는 방법의 톤 그러나 여기에서 간단한 일이다 ...

class Program 
{ 
    static void Main() 
    { 
     var simpleFactory = new SimpleFactory(); 
     var entity = simpleFactory.Create(1); 
     entity.Something(); 
    } 
} 

public abstract class EntityBase 
{ 
    public abstract ushort ID { get; } 
    public abstract void Something(); 
} 

public class TestEntity : EntityBase 
{ 
    public override ushort ID { get { return 1; } } 
    public override void something() { } 
} 
public class OtherEntity : EntityBase 
{ 
    public override ushort ID { get { return 2; } } 
    public override void something() { } 
} 

public class SimpleFactory 
{ 
    private Dictionary<ushort, Func<EntityBase>> config = new Dictionary<ushort, Func<EntityBase>> 
    { 
     { 1,()=>new TestEntity()}, 
     { 2,()=>new OtherEntity()}, 
    }; 

    public EntityBase Create(ushort entityId) 
    { 
     if (!config.ContainsKey(entityId)) 
      throw new InvalidOperationException(); 

     return config[entityId](); 
    } 
} 
+1

리플렉션을 피하기 위해 람다 사용에 +1을받습니다. –

+0

나는이 패턴을 좋아한다. 왜냐하면 만약 그렇지 않다면 ...'T Create ()와 같은 생성자에 매개 변수를 제공하는 것이 쉽기 때문이다. T class, new() {...}' –