Recomposition
 
이전 포스트의 MEF 의 특징 중에 MEF 의 플러그인 모델(Plugin Model) 은 교체가 용이하다고 하였습니다. Composable Part 는 구성 요소로써 고유의 기능을 구현합니다. 그리고 MEF 는 각각의 Composable Part 를 조립하여 다양한 컴포넌트 또는 애플리케이션을 완성합니다.
 
어떠한 경우에는 특정한 구성 구성요소를 사용하다가 그것이 필요 없어질 경우 구성 요소를 언로드(Unload) 하거나 다른 구성요소로 교체할 필요가 있습니다.
 
MEF 의 이러한 유연함의 예를 들어보죠.
 
예를 들어, 어플리케이션의 로그(Log) 기능을 생각해볼 수 있습니다. 만약 어플리케이션이 동작하는 환경이 인터넷에 연결되지 않는 환경이라면 사용자의 컴퓨터 로컬에 로그를 기록하다가, 인터넷에 연결될 경우 외부 데이터베이스로 로그를 기록하는 시나리오를 가정할 수 있습니다. 그리고 이러한 기능 또는 요구 사항이 언제 변경될지도 모르는 일입니다.
 
일단 위의 시나리오를 구현하기 여러 가지 고려해야 할 사항이 있고, 기능 또는 요구 사항이 변경될 경우도 고려해야 합니다. 결국, MEF 는 이러한 변화에 굉장히 유연하게 대처할 수 있습니다.
 
MEF 에서 ImportAttribute 의 AllowRecomposition 프로퍼티를 통해 구성 요소를 런타임(Runtime) 시 동적(Dynamic) 으로 교체할 수 있도록 합니다.
 
아래는 위의 예로 든 시나리오를 구현하기 위해 작성한 간단한 소스 코드 입니다.
 
ILogger 인터페이스
public interface ILogger
{
        void Write();
}
 
ILogger 인터페이스는 Write 메서드를 통해 로그를 기록할 수 있는 예입니다.
 
 
TextLogger 클래스
[Export(typeof(ILogger))]
public class TextLogger : ILogger
{
        public void Write()
        {
               Console.WriteLine("Logged TextLogger");
        }
}
 
 
DatabaseLogger 클래스
[Export(typeof(ILogger))]
public class DatabaseLogger : ILogger
{
        public void Write()
        {
               Console.WriteLine("Logged DatabaseLogger");
        }
}
 
 
LoggerContext 클래스
[Export]
public class LoggerContext
{
        [Import(AllowRecomposition=true)]
        public ILogger Context { get; set; }
 
        [ImportingConstructor]
        public LoggerContext(ILogger sender)
        {
        }
}
 
여기에서 ImportAttribute 의 AllowRecomposition 프로퍼티의 값을 true 로 지정해 주었습니다. AllowRecomposition 프로퍼티가 true 일 경우 Imported 된 구성 요소를 동적(Dynamic)하게 교체할 수 있도록 합니다.
 
 
Main 어플리케이션
class Program
{
        static void Main(string[] args)
        {
               Program p = new Program();
               p.Run();
        }
 
        void Run()
        {
               var catalog    = new AggregateCatalog(new TypeCatalog(typeof(LoggerContext)));
 
               var container = new CompositionContainer(catalog);
               var batch = new CompositionBatch();
               var defaultPart = batch.AddPart(new TextLogger());
               container.Compose(batch);
 
               var obj = container.GetExportedObject<LoggerContext>();
 
               obj.Context.Write();
              
               batch = new CompositionBatch();
               batch.RemovePart(defaultPart);
               batch.AddPart(new DatabaseLogger());
               container.Compose(batch);
 
               obj.Context.Write();
        }
}
 
이 코드는 처음에 TextLogger 를 사용하다가, 필요 없어진 TextLogger 를 제거하고 DatabaseLogger 로 교체하는 코드입니다.
 
아래는 위의 소스 코드를 실행한 결과입니다.
 

[그림1] 소스 코드 실행 결과
 
 
Wow! Recomposition
 
사실 이러한 것이 기존에는 기능의 정의 또는 요구 사항에 따라 직접 구현할 수 있었지만, MEF 의 특징인 플러그인 모델(Plugin Model) 은 이러한 고민에 대해 좋은 방법을 제공해 줍니다. 개발자는 자신이 구현해야 할 기능에 더 충실하고, 비즈니스 로직에 대한 고민만을 하면 됩니다. 그리고 정책에 따라 그것을 집행하는 결정권을 가진 자는 구현된 구성 요소를 조립하고 교체하여 기존의 정적인(Static) 어플리케이션에게 동적인(Dynamic) 유연함을 제공합니다.
 
기존에 정적인 어플리케이션은 변화에 따라 유지 보수를 위해 지속적인 많은 리소스가 필요하였지만, 플러그인 모델(Plugin Model) 의 동적인 어플리케이션은 그러한 변화에 능동적으로 대처할 수 있는 큰 기쁨을 줄 수 있을 것입니다.
저작자 표시 비영리 동일 조건 변경 허락
신고

'.NET > .NET Framework' 카테고리의 다른 글

MEF 세미나 자료  (0) 2009.06.22
[MEF] 10. Querying the Composition Container  (0) 2009.05.17
[MEF] 9. Recomposition  (2) 2009.04.20
[MEF] 8. Strongly Typed Metadata  (0) 2009.04.17
[MEF] 7. Exports and Metadata  (1) 2009.04.16
[MEF] 6. Lazy Exports  (0) 2009.04.13
Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. 윤성민 2009.07.26 17:18 신고 Address Modify/Delete Reply

    꼭 MEF가 아니더라도 상기 예제는 Interface만으로도 구현이 가능하지 않을까요?
    그것과 MEF가 가지는 장점은 무엇인지가.. 개인적으로 궁금합니다.

    • 땡초 POWERUMC 2009.07.26 23:44 신고 Address Modify/Delete

      이미 윤성민님께서 "~가능하지 않을까?" 라는 고민에 MEF 가 가이드를 제시해 주고 있습니다.
      (직접 구현한다면 불가능한 것이 없겠습니다만)
      DI/IoC 와 Addin Framework 의 불편함을 겪어 보셨다면 이미 충분한 답이 될 것 같습니다.

      그래도 제가 생각하는 MEF 의 최대 장점은 Composable 이 아닐까 생각합니다.
      이미 WPF 에서도 이러한 Composable 한 패턴을 위해 MVVM 등으로 풀어가는 단적인 예만 본다면,
      단지 Object 로만 바라보던 기존 패러다임과는 분명히 다르지 않겠습니까?? ^^

      세미나 발표 자료에서 언급했듯이 IoC+Addin=MEF 외에도 Composable 로 인하여 1:n, 조립, 결합, 구성이라는 장점을 누릴 수 있습니다.