Singleton Management
Prism은 IContainerRegistry를 통해 Singleton 인스턴스 객체를 지속 관리할 수 있습니다. IContainerRegistry는 기본적으로 PrismApplication 클래스로 부터 강제 구현되기 때문에 어려움 없이 사용할 수 있습니다. (abstract)
override 타입인 RegisterTypes 메서드를 통해 IContainerRegister를 사용할 수 있습니다.
internal class App : PrismApplication
{
...
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
// 여기!!
}
}
허나! 기존 Application을 유지하면서 PrismBootstrapper를 사용할 경우도 있겠죠. 이 경우 PrismBootstrapper 에서도 또한 RegisterTypes 메서드를 override할 수 있으므로 동일하다 생각하면 됩니다. 크게 다를 것이 없기에, 이 부분은 나중에 좀 더 다뤄보도록 하겠습니다.
IContainerRegistry
이제 Singleton 인스턴스를 관리하기 위해 해당 객체를 등록해야 합니다. 이 때 사용되는 메서드가 바로 RegisterSingleton 입니다. 그럼 RegisterSingleton 메서드를 어떻게 사용할 수 있는지 한번 살펴보겠습니다.
바로생성하기
Application 생성 과정에서 바로 인스턴스를 생성하는 경우입니다. 실제 new() 생성이 발생하기 때문에 Singleton을 등록하는 과정에서 굳이 생성할 필요가 없거나 하지 말아야 하는 경우를 잘 판단해 보는 것이 좋습니다.
containerRegistry.RegisterSingleton(new AvatarView());
아마도 변수가 필요한 생성자 이거나 무언가 셋팅이 필요하거나, 여러 시점 상의 이유가 있을 수 있겠죠.
그리고 인스턴스를 문자열로 접근할 때 원하는 이름으로 찾을 수 있도록 부여하는 것도 가능합니다. (overriding)
containerRegistry.RegisterSingleton(new BlogView(), "BlogPage");
containerRegistry.RegisterSingleton<AvatarView>(new AvatarView(), "BlogPage");
두번째 줄은
<T>
타입 단순화가 가능하죠!
사실 기본적으로 이름을 작성하지 않는다면 객체 이름과 동일한 AvatarView 문자열이 부여되지만, 이렇게 인스턴스명과 다르게 등록할 수도 있겠습니다. 아마도 보통 접두 단어를 붙이거나 할 때 사용되겠죠.
타입등록하기
바로 생성하는 방법과는 달리 Singleton 인스턴스를 등록하는 과정에서 객체를 생성할 필요가 없거나 ViewModel 의존성 주입, Resolve, Region 등에서 호출이 될 때 생성되어야 할 경우에는 바로 이 방법에 해당하게 됩니다. 물론 시점 상 더 다양한 경우가 있겠습니다.
container.Registry.RegisterSingleton(typeof(BlogView));
앞서 인스턴스를 생성하는 것과는 달리 <T>
타입을 넘겨줌으로써 먼 훗날… BlogView를 찾는 상황이 생길 때 Singleton 관리 객체가 생성될 것입니다. 그리고 이번에도 마찬가지로 name을 원하는 문자열로 부여할 수 있습니다.
container.Registry.RegisterSingleton(typeof(BlogView), "BlogViewPage");
이렇게 하면 Type을 통해 Singleton 객체를 등록만 해서 어디선가 사용되기를 기다리기만 하면 됩니다.
Singleton 사용
그럼 이제 ViewModel이나 Resolve<T>
를 통해 등록된 Singleton 객체를 가져와볼까요?
ViewModel에서 IoC Container 주입을 통한 사용방법입니다.
public class JamesViewModel(BlogView blogView)
{
}
Resolve를 통한 사용 방법도 크게 다르지 않습니다.
BlogView blogView = _container.Resolve<BlogView>("BlogViewPage");
BlogView galleryView = _container.Resolve<GalleryView>();
BlogView aboutView = _container.Resolve<AboutView>();
Region에 추가하거나 목적에 맞게 다양하게 활용하겠습니다. (Singleton 관리가 필요한 View인 경우 재미있게 응용할 수 있죠.)
Interface 활용
사실 Singleton을 사용하기 위해서는 등록에 사용된 객체 타입을 알고 있어야만 하는 구조적인 불편함이 생깁니다. 프로젝트 구조상, 별 상관없는 경우도 있겠지만 복잡하게 여러 프로젝트를 참조해야 하는 경우에는 이 활용이 필요합니다.
기존 Singleton 방식과 거의 동일 하면서 대표 인터페이스(또는 클래스)를 정의할 수 있습니다.
container.Registry.RegisterSingleton<IViewable, BlogView>("Blog");
container.Registry.RegisterSingleton<IViewable, GalleryView>("Gallery");
container.Registry.RegisterSingleton<IViewable, AboutView>("About");
이렇게 인터페이스 또는 상위 상속클래스를 대표 타입으로 정의한다면 아래처럼 어떠한 참조 없이도 대표 타입을 통해 객체를 가져올 수 있습니다.
_container.Resolve<IViewable>("Blog");
_container.Resolve<IViewable>("Gallery");
_container.Resolve<IViewable>("About");
이를 통해 프로젝트간 참조 관계와 상관 없이도 Singleton을 편하게 사용할 수 있습니다.
읽어주셔서 감사합니다.