2017-01-27 8 views
0

첫째, 나는이 질문의 제목을 붙이기 위해 고심 했으므로 더 나은 아이디어가 있다고 생각한다면 먼저 편집하십시오.비 제너릭 클래스에 제네릭 생성

이것은 내가 몇 번이고 뛰어 다니며 우회하는 악취를내는 것으로 끝나는 문제인 것 같습니다. 일반적인 형식은 무언가 (예 : 팩토리)의 인스턴스를 가져 오기위한 비 제너릭 클래스가 있지만 인스턴스의 유형에 대한 결정이 필요하다는 것입니다. 아래 예제에서는 내가 무엇을 설명하는지 보여 주지만, 컴파일되지 않는다는 것을 알게 될 것입니다. 왜냐하면 FooBarFactory에서 AbstractThingT으로 사용할 수 없기 때문에 추상화는 허용되지 않기 때문입니다. 그렇다면 어떻게하면 FooBarFactory을 런타임에 Generator<T>이 T에 사용해야하는 유형으로 결정하게 할 수 있습니까?

public class FooBarFactory 
{ 
    private Generator<AbstractThing> _generator; 

    public AbstractThing GetThing(string data, ThingType type) 
    { 
     switch (type) 
     { 
      case ThingType.Foo: 
       _generator = new FooGenerator(); 
       break; 

      case ThingType.Bar: 
       _generator = new BarGenerator(); 
       break; 

      case ThingType.None: 
       return null; 

      default: 
       throw new ArgumentOutOfRangeException(nameof(type), type, null); 
     } 

     return _generator.Generate(data); 
    } 
} 

public abstract class Generator<T> where T : AbstractThing, new() 
{ 
    protected T GeneratedThing = new T(); 

    protected abstract void MapDataToThing(string data); 

    public T Generate(string data) 
    { 
     MapDataToThing(data); 
     return GeneratedThing; 
    } 
} 

public class FooGenerator : Generator<Foo> 
{ 
    protected override void MapDataToThing(string data) 
    { 
     GeneratedThing.AbstractProp = ParseAbstract(data); 
     GeneratedThing.FooProp = ParseFoo(data); 
    } 

    private static string ParseAbstract(string data) 
    { 
     throw new NotImplementedException(); 
    } 

    private static string ParseFoo(string data) 
    { 
     throw new NotImplementedException(); 
    } 
} 

public class BarGenerator : Generator<Bar> 
{ 
    protected override void MapDataToThing(string data) 
    { 
     GeneratedThing.AbstractProp = "Base property in Bar"; 
     GeneratedThing.BarProp = data.Substring(4, 3); 
    } 
} 

public abstract class AbstractThing 
{ 
    public string AbstractProp { get; set; } 
} 

public class Foo : AbstractThing 
{ 
    public string FooProp { get; set; } 
} 

public class Bar : AbstractThing 
{ 
    public string BarProp { get; set; } 
} 

public enum ThingType 
{ 
    None = 0, 
    Foo = 1, 
    Bar = 2 
} 
+1

제네릭의 주 목적은 * 컴파일 타임 * 유형 안전을 제공하는 것입니다. "FooBarFactory가 Generator 이 T에 사용해야하는 유형을 런타임에 결정하게하십시오."는 의미가 없습니다. – mm8

+0

@ mm8 - 내 의도는 공장에서 AbstractThing을 반환하도록하는 것이 었습니다. 여기서 무엇을 권하고 싶습니까? 공장에는 AbstractThing의 각 하위 유형에 대한 메소드가 있어야합니까? 또는 공장에 Generator의 인스턴스가 없어야하며 대신 각 사례 블록 내에 적절한 Generator를 새로 작성해야할까요? – bubbleking

+0

일반 생성기가 필요하지 않습니다. 나는 대답을 올렸다. – mm8

답변

1

제네릭의 주요 목적은 컴파일시 유형의 안전을 제공하는 것입니다. "FooBarFactory가 런타임에 Generator<T>이 사용해야하는 유형을 T에 대해 결정하도록하십시오"는 의미는 없습니다.

제 의도는 공장에서 AbstractThing을 반환하도록하는 것이 었습니다.

이것은 반환 유형이 AbstractThing 인 팩토리 메소드에 의해 적용됩니다.

여기에 무엇을 권하고 싶습니까? 공장에는 AbstractThing의 각 하위 유형에 대한 메소드가 있어야합니까?

GetThing 방법, 즉 팩토리 메소드, 단순히이 푸 또는 바 개체를 반환할지 여부를 결정하는 제네릭이 아닌 공장 자체 즉, 당신의 일부 논리를 기반으로 AbstractThing를 반환해야합니다. Generics는 실제로 여기에 적용되지 않습니다.

공장에서 Generator의 인스턴스가 없어야하며 대신 각 사례 블록 내에 적절한 Generator를 새로 추가해야합니까?

발전기 클래스가 반드시 필요한 것은 아닙니다. 원하는 경우 Foo 또는 Bar을 팩토리 메서드 자체에서 직접 만들어야하는지 여부를 결정하는 논리를 구현할 수 있습니다. 팩토리는 N 개의 매개 변수를 입력으로 사용하고 공장에서 추상화 된 일부 논리를 기반으로 AbstractThing 유형의 구체적인 구현을 반환합니다.

희망이 있습니다.

+0

그래, 모두 의미가있다. 아마 내가 때때로하는 것처럼 나는 단지 지나치게 복잡한 것들이라고 생각합니다. – bubbleking