2011-08-19 4 views
4

이 (이것은 물론 실제 코드는 아니지만이 같은 특성이있다) 코드로 설명 할 아마도 가장 쉬운 방법입니다 : 내가 뭔가를 보이는 인터페이스가구현 클래스가 봉인 될 때 ​​단일 인터페이스 메서드를 재정

을 같은 :

이제
//NOTE: Sealed class otherwise we could inherit from it 
    public sealed class SuperCleverProvider : ISomeProvider 
    { 
     public object GetFoo1() 
     { 
      return "a"; 
     } 

     public object GetFoo2() 
     { 
      return "b"; 
     } 

     public object GetFoo3() 
     { 
      return "b"; 
     } 
    } 

이러한 호출 중 하나의 그래서 난 공급자에 원하는 GetFoo1 정말 무거운 가정 해 봅시다 :

public interface ISomeProvider 
    { 
     object GetFoo1(); //<-- This needs caching 

     //These others don't 
     object GetFoo2(); 
     object GetFoo3(); 

     //And let's say 20 more 
    } 

을 그리고이 이와 같은 구현이 이전 버전의 인스턴스를 사용하여 호출을 캐시하는 인터페이스의 새 버전입니다.

나는 순간에 이런 식으로 일을 해요 :

public class CachedSuperCleverProvider : ISomeProvider 
    { 
     private readonly SuperCleverProvider _provider; 

     public CachedSuperCleverProvider(SuperCleverProvider provider) 
     { 
      _provider = provider; 
     } 

     private object UsingCache<T>(string cacheKey, Func<T> eval) 
     { 
      //Pretend this does caching. This is not related to the question 
      throw new NotImplementedException(); 
     } 

     public object GetFoo1() 
     { 
      return UsingCache("foo1", _provider.GetFoo1); 
     } 

     //The code below this point is what I want to get rid of 
     public object GetFoo2() 
     { 
      return _provider.GetFoo2(); 
     } 

     public object GetFoo3() 
     { 
      return _provider.GetFoo3(); 
     } 

     //And so on for all the rest 
    } 

이 (적어도) 두 가지 문제가 있습니다

  • 때마다 누군가가 내가 가야 인터페이스에 메소드를 추가를 이 새로운 메서드가 캐시되지 않게하려면이 코드를 변경하십시오.
  • 나는이 기본 코드를 호출하는 쓸모없는 코드 목록을 얻었습니다.

누구나 이러한 문제가없는 방법을 생각할 수 있습니까?

+0

올바른 방법은 캡슐화를 통한 상속입니다.유지하는 임무이지만 컴파일러는이 클래스 중 하나가 오래된 경우 알려줍니다. –

답변

3

세 가지 옵션 :

  • 자동 생성 클래스
  • 사용 PostSharp 또는 개인적으로

나는 것와

  • 라이브 더 인터셉터 기반 방법으로 그것을 할 비슷한 정말로이 일을 많이하지 않는 한 세 번째 옵션을 사용하는 것이 좋습니다. 각 옵션의 비용을 재검토하십시오. 얼마나 많은 시간입니까? 실제로이 위임을 추가하려고합니까?

    개인적으로 나는이 언어 기능으로 물건의 종류 볼 수 같은 을 거라고 -하지만 분명 그 순간에 존재 아니다 "나는 그것을 무시하지 않는 한이 필드를 통해이 인터페이스에 대리자를"...

  • 0

    여기 내가 제안 할 것이있다. 그다지 좋지는 않지만 래핑 과정을 단순화합니다.

    클래스 SomeProviderWrapper 만들기 :

    public class CachedSuperCleverProvider : SomeProviderWrapper 
    { 
        public CachedSuperCleverProvider(ISomeProvider wrapped) : base(wrapped) { } 
    
        private object UsingCache<T>(string cacheKey, Func<T> eval) 
        { 
         throw new NotImplementedException(); 
        } 
    
        public override object GetFoo1() 
        { 
         return UsingCache("foo1", WrappedProvider.GetFoo1); 
        } 
    } 
    

    이 당신의 슈퍼에서 위임 코드를 유지 : 이제 포장이 자신의 클래스에 이관되는 것을

    public class SomeProviderWrapper : ISomeProvider 
    { 
        protected ISomeProvider WrappedProvider { get; private set; } 
    
        protected SomeProviderWrapper(ISomeProvider wrapped) 
        { 
         if (wrapped == null) 
          throw new ArgumentNullException("wrapped"); 
    
         WrappedProvider = wrapped; 
        } 
    
        public virtual object GetFoo1() 
        { 
         return WrappedProvider.GetFoo1(); 
        } 
    
        public virtual object GetFoo2() 
        { 
         return WrappedProvider.GetFoo2(); 
        } 
    
        public virtual object GetFoo3() 
        { 
         return WrappedProvider.GetFoo3(); 
        } 
    } 
    

    , 당신은 캐싱 버전을 쓸 수를 영리한 공급자. 여전히 위임 코드를 유지해야하지만 캐싱 공급자의 디자인을 오염시키지는 않습니다.

    관련 문제