2014-02-10 4 views
5

우리는 다음과 같은 클래스를 가지고, 이제 가정하자.리팩토링

모두를 하나의 제네릭 클래스로 변환하는 좋은 방법이 있습니까? C 번호는 일반적인 수준의 전문화에 매개 변수화 ctors를 호출 허용하지

proxy = new ProxyA(data); 

때문에 (T 기준) : 핵심 문제는 라인입니다.

+0

DoSth를 변경하여 데이터 값을 가져올 수 있습니까? –

+0

@PhillipTrelford 할 수 없습니다. 'Proxy' 객체는이 클래스 (그리고 그것을 사용하는 객체)에서 매우 중요합니다. – Spook

답변

1

형식을 알고 있으면 (원하는 경우 제네릭을 사용하여) Activator.CreateInstance을 호출하여 원하는 생성자를 사용하여 해당 형식의 인스턴스를 만들 수 있습니다.

proxy = Activator.CreateInstance(typeof(TProxy), new[]{data}); 

이이 직접 문제를 해결할 수 있지만, 당신은 또한 ProxyA를 전달되는 대신에 대한 DataA을 알고하지 않습니다 ViewModelA 디자인에 대해 생각 할 수있다. 그것은 멋진 반영없이 모든 문제를 해결할 것입니다.

+0

ProxyA를 전달하면 ProxyA의 범위가 ViewModel의 소유자로 확장되므로 캡슐화가 중단됩니다. 그게 효과가 있을지 모르지만 나는 그것을 멋진 솔루션이라고 부를 수는 없다. Activator.CreateInstance는 더 이상 보이지는 않지만 (특히 ViewModel 클래스를 몇 번만 구성하면 단 한 번 발생하므로 반사를 사용하는 데 너무 많은 시간을 낭비하지 않습니다) – Spook

+0

리플렉션을 사용하기로 결정했습니다. 이러한 작업은 몇 번만 수행되므로 성능이 떨어지지 않고 솔루션이 나에게 충분합니다.다른 해결책은 비록 가치가있다. – Spook

0
public interface IDoSomething 
{ 
    void DoSth(); 
} 

class ViewModel<T> where T : IDoSomething 
{ 
    private T proxy; 

    public ViewModel() 
    { 
     proxy = Activator.CreateInstance<T>(); 
    } 

    //public ViewModel(T data) 
    //{ 
    // proxy = data; 
    //} 

    public void DoSth() 
    { 
     proxy.DoSth(); 
    } 

    public T Proxy 
    { 
     get 
     { 
      return proxy; 
     } 
    } 
} 
+0

'ViewModel' 클래스의 논리가 깨졌습니다 -'Proxy'가 아닌'DoSth'를 담당합니다. 또한 간단히 :'T : BaseProxy, new()'가 필요하다면 리플렉션을 사용하지 않아도됩니다. 매개 변수없는 ctors는 일반 클래스 전문화에 호출 될 수 있습니다. – Spook

1

언급 한대로 리플렉션을 사용하지 않고 매개 변수화 된 생성자에서는이 작업을 수행 할 수 없습니다. 그러나이 주제에 대한 하나의 가능한 변화 :

public interface IDataProxy<T> 
{ 
    T Data { get; set; } 
} 

public class ViewModel<TProxy, TData> 
    where TProxy : class, new, IDataProxy<TData> 
{ 
    public TProxy Proxy { get; private set; } 

    public ViewModel(TData data) 
    { 
     Proxy = new TProxy { Data = data }; 
    } 
} 
+0

프록시가 인터페이스를 구현할 수 있다고 가정합니다. 불합리하지는 않지만 가끔은 할 수 없습니다. – Thorarin

+0

+1, 아주 좋은 해결책입니다. 단점은 (@Thorarin이 말한 것과는 별도로), 코드 청결을 위해 프록시가 데이터를 첨부하지 않고 작업하는 방법을 가르쳐야한다는 것입니다. 하지만 아마도 그만한 가치가 있을까요? – Spook

0
public interface IProxy 
{ 
    void DoSth(); 
} 

public class ProxyA : IProxy 
{ 
    public ProxyA(DataA dataA) 
    { 

    } 
    public void DoSth() 
    { } 
} 

public class ProxyB : IProxy 
{ 
    public ProxyB(DataB dataA) 
    { 

    } 
    public void DoSth() 
    { 

    } 
} 

public class ViewModel<T> where T : IProxy 
{ 
    private readonly IProxy _proxy; 
    public ViewModel(T proxy) 
    { 
     _proxy = proxy; 
    } 

    public void DoSth() 
    { 
     _proxy.DoSth(); 
    } 
} 

var vm = new ViewModel<ProxyA>(new ProxyA(new DataA())); 
vm.DoSth(); 
+0

캡슐화를 깨는'ViewModel'의 소유자에게'Proxy'의 가시성을 확장했기 때문에 괜찮습니다. (소유자는'ViewModel'의 로컬에 대해 아무것도 알지 않아야합니다. 관련 클래스). – Spook

2

당신은 미리 구성된 ProxyA 또는 ProxyB 객체를 전달하여이 문제를 해결할 수 있습니다. 그 일의

한 가지 방법은 기본 생성자를 호출하기 전에 객체를 구성, 상속을 통해입니다 :

class ViewModel<TProxy, TData> 
{ 
    private TProxy proxy; 

    public ViewModel(TProxy proxy) 
    { 
     this.proxy = proxy; 
    } 

    public void DoSth() 
    { 
     proxy.DoSth(); 
    } 

    public TProxy Proxy 
    { 
     get 
     { 
      return proxy; 
     } 
    } 
} 

class ViewModelA : ViewModel<ProxyA, DataA> 
{ 
    public ViewModelA(DataA data) : base(new ProxyA(data)) 
    { 
    } 
} 

내가 DataADataB는 생략 한 메소드 서명 어딘가에서 발생하는 여기에 가정했습니다. 그렇지 않은 경우 TData 제네릭 유형 매개 변수를 생략 할 수 있습니다.

반사는 항상 옵션이지만, 이와 같은 해결책이 허용되는 경우에는 피해야합니다.

ViewModel(TData data, Func<TData, TProxy> factory) : this(factory(data)) 
{ 
} 

하는 등 사용 :

new ViewModel<ProxyA, DataA>(new DataA(), data => new ProxyA(data)); 

내가 잘 모르겠어요 다른 TProxyTData을위한 새로운 유형을 만들 필요가 없도록하려는 경우, 당신은 대신 두 번째 생성자를 추가 할 수 있습니다 그러나 그것은 당신의 응용 프로그램에서 할 말이 있습니다.

+0

나는 할 수있다 : 1. 내부에서 생성 된 유일한 프록시 객체가 아니기 때문에 모든 것을 ctor에 전달해야한다. 2. 캡슐화를 깨는'ViewModel' 소유자에게'Proxy' 클래스의 범위를 확장해야합니다 (이 경우'Proxy'는 애플리케이션 로직 때문에 ViewModel의 소유자에게는 보이지 않지만 구현상의 세부 사항 때문에) . 그게 효과가 있지만 좋은 * 솔루션이라고 부를 수는 없습니다 :) – Spook

+0

+1 공장. ViewModel (IMO) 내부에서 프록시를 전달하는 것보다 훨씬 좋은 해결책입니다. – Spook