### **팩토리 등록 (Registering Factories)**
- **필요성:** VContainer는 일반적으로 등록된 의존성을 처음 해결할 때 구성합니다(이미 등록된 인스턴스는 제외). 만약 의존성 생성 시점에 대해 더 세밀한 제어가 필요하다면, 팩토리 함수를 등록하고 사용할 수 있습니다.
- **정의:** 팩토리 함수는 다른 의존성처럼 해결되는 `Func<>` 델리게이트입니다. 이들은 언제든지 하나 이상의 다른 의존성을 생성하는 데 사용될 수 있습니다.
**참고:** 팩토리가 "생성"을 의미하는 이름에도 불구하고, 새로운 객체를 생성하는 대신 기존 객체를 반환할 수도 있습니다. 이는 동일한 타입의 여러 의존성을 다른 키에 매핑할 때 유용할 수 있습니다(예: 로컬 멀티플레이어 게임에서 각 플레이어에 대한 고유한 컨트롤러 서비스).
**기본 팩토리 예시:**
C#
```
class FooFactory
{
// 생성자 주입을 통해 의존성(DependencyA)을 받음
public FooFactory (DependencyA dependencyA)
{
this.dependencyA = dependencyA;
}
// Foo 객체를 생성하는 메서드
public Foo Create(int b) => new Foo(b, dependencyA);
}
// 등록
builder.Register<FooFactory>(Lifetime.Singleton); // FooFactory 자체를 컨테이너에 등록
// 사용
var factory = container.Resolve<FooFactory>(); // 의존성 해결은 여기서 발생
var foo1 = factory.Create(1); // 여기서 새로운 Foo 객체가 생성되며, 추가적인 의존성 해결은 필요 없음
var foo2 = factory.Create(2);
var foo3 = factory.Create(3);
```
- **설명:** `FooFactory`는 `DependencyA`에 의존하며, `Create` 메서드를 통해 `Foo` 객체를 생성합니다. `FooFactory`는 컨테이너에 `Singleton`으로 등록되어 한 번만 생성됩니다. `Create` 메서드가 호출될 때는 VContainer의 의존성 해결이 다시 발생하지 않고, `FooFactory`가 이미 주입받은 `dependencyA`를 활용하여 `Foo` 객체를 생성합니다.
**런타임 의존성 주입을 포함하는 팩토리:**
팩토리 내부에서 `IObjectResolver` API를 명시적으로 사용하여 런타임에 다른 의존성을 해결할 수도 있습니다.
C#
```
builder.Register<IFooFactory>(container =>
{
// 이 람다 함수는 IFooFactory가 처음 해결될 때 한 번 실행됩니다.
// 여기서 IFooFactory 인스턴스가 생성됩니다.
return new FooFactoryWithRuntimeDeps(container.Resolve<SomeOtherDependency>());
}, Lifetime.Singleton);
class FooFactoryWithRuntimeDeps : IFooFactory
{
private readonly SomeOtherDependency _someOtherDependency;
public FooFactoryWithRuntimeDeps(SomeOtherDependency someOtherDependency)
{
_someOtherDependency = someOtherDependency;
}
public IFoo CreateFoo(int id)
{
// 런타임에 필요한 다른 의존성을 여기서 Resolve할 수 있습니다.
// 예를 들어, 매번 다른 설정을 가진 Foo를 생성하고 싶을 때 유용합니다.
// 하지만 이 방식은 Resolve가 런타임에 발생하므로 성능에 영향을 줄 수 있습니다.
// 가능한 한 생성자 주입을 통해 의존성을 미리 주입받는 것이 좋습니다.
return new Foo(id, _someOtherDependency.GetDataForFoo(id));
}
}
```
- **설명:** 델리게이트를 통해 `IFooFactory`를 등록합니다. 이 델리게이트는 `IObjectResolver`를 인자로 받아 `SomeOtherDependency`를 해결하고, 이를 사용하여 `FooFactoryWithRuntimeDeps`를 생성합니다. 이렇게 생성된 팩토리는 `CreateFoo` 메서드 내부에서 추가적인 런타임 의존성 해결 로직을 가질 수 있습니다.
**제네릭 팩토리 (Generic Factory):**
동적으로 다양한 타입의 객체를 생성해야 할 때 제네릭 팩토리를 사용할 수 있습니다.
C#
```
// 캐릭터 타입에 따라 다른 CharacterActor를 생성하는 팩토리
builder.Register<Func<CharacterType, CharacterActor>>(container =>
{
return characterType =>
{
GameObject characterPrefab;
// characterType에 따라 다른 프리팹 선택 로직
if (characterType == CharacterType.Warrior)
{
characterPrefab = warriorPrefab;
}
else
{
characterPrefab = magePrefab;
}
// IObjectResolver.Instantiate를 사용하여 프리팹을 인스턴스화하고 의존성 주입
return container.Instantiate(characterPrefab, parentTransform);
};
}, Lifetime.Scoped);
```
- **설명:** `Func<CharacterType, CharacterActor>` 타입의 팩토리를 등록합니다. 이 팩토리는 `CharacterType`을 입력받아 적절한 프리팹을 선택하고, `container.Instantiate`를 사용하여 `CharacterActor` 인스턴스를 생성하며 자동으로 의존성을 주입합니다.
**팩토리 메서드 등록 (Registering factory methods):**
클래스 내부에 정의된 팩토리 메서드를 `Func<>` 델리게이트처럼 컨테이너에 등록할 수 있습니다.
C#
```
class FooFactory
{
readonly DependencyA dependencyA;
public FooFactory (DependencyA dependencyA)
{
this.dependencyA = dependencyA;
}
public Foo Create(int b) => new Foo (b, dependencyA);
}
builder.Register<FooFactory>(Lifetime.Singleton); // FooFactory 자체를 등록
// FooFactory의 Create 메서드를 Func<int, Foo> 델리게이트로 등록
builder.RegisterFactory(container => container.Resolve<FooFactory>().Create, Lifetime.Singleton);
// 사용
var factory = container.Resolve<Func<int, Foo>>(); // 팩토리 델리게이트를 가져옴
var foo1 = factory(1);
var foo2 = factory(2);
var foo3 = factory(3);
var originalFactoryObject = container.Resolve<FooFactory>(); // 필요하다면 원본 팩토리 객체도 가져올 수 있음
// 만약 FooFactory가 IDisposable을 구현했다면, IObjectResolver가 Dispose될 때 Dispose()가 호출됩니다.
```
- **설명:** `FooFactory` 클래스를 등록한 후, `RegisterFactory`를 사용하여 `FooFactory` 인스턴스의 `Create` 메서드를 `Func<int, Foo>` 타입으로 컨테이너에 등록합니다. 이렇게 하면 외부에서 `FooFactory` 클래스 자체에 대한 지식 없이도 `Func<int, Foo>` 델리게이트를 주입받아 `Foo` 객체를 생성할 수 있습니다.
### 요약
VContainer에서 팩토리를 사용하여 의존성 객체 생성을 동적으로 제어하는 다양한 방법을 제시합니다. 여기에는 `Func<>` 델리게이트를 사용한 기본 팩토리, `IObjectResolver`를 활용하여 런타임 의존성을 주입하는 팩토리, 제네릭 팩토리, 그리고 기존 클래스의 메서드를 팩토리로 등록하는 방법이 포함됩니다. 팩토리는 특히 게임에서 프리팹 인스턴스화나 동적인 객체 생성 로직이 필요한 경우에 강력한 패턴으로 활용될 수 있습니다.
---
이전 : [[4.2 Register using delegate]] | 다음 : [[4.4 Register MonoBehaviour]]