2021. 5. 7. 22:29
https://blog.naver.com/nagne2011/222341989853
ZenJect - 의존성 주입
#ZenJect https://github.com/modesttree/Zenject "유니티에서 사용할수 있는 'IOC에셋&#x...
blog.naver.com
#ZenJect
https://github.com/modesttree/Zenject
"유니티에서 사용할수 있는 'IOC에셋'"
"DI패턴을 구현"
"의존성 주입 가능"
zenject에 대한 타이틀이다
즉, 의존성 주입 패턴 DI패턴을 구현하는 방식이다
https://medium.com/@jang.wangsu/di-dependency-injection-%EC%9D%B4%EB%9E%80-1b12fdefec4f

디펜던시 인젝션, 의존성 주입에 대해 간단하게 작성해 봅니다.
medium.com
이걸 왜 사용할까??
아래 예시를 보자

사진 설명을 입력하세요.
3개의 텍스트가 있다
각각 회원정보 중 이름, 나이, 국가를 텍스트에 표시해보자
방법에는 여러가지가 있겠지만..
기본적으로 가장 간단한 방법은 스크립트로 직접 추가하는방식이다
User, Information 두개의 스크립트를 만들어서 각각 입력해준다음
public class User : MonoBehaviour
{
public string Name = "테스터";
public string Age = "19세";
public string Nation = "kor";
}
public class Information : MonoBehaviour
{
public User m_user;
public Text m_userName;
public Text m_userAge;
public Text m_userNation;
private void Start()
{
m_userName.text = m_user.Name;
m_userAge.text = m_user.Age;
m_userNation.text = m_user.Nation;
}
}

사진 설명을 입력하세요.
이렇게 입력하면 끝
근데 여기서,
해당 정보를 쓰는곳이 많다면? information스크립트가 information2, information3, information4 등등 매우 다양해진다면?
User스크립트를 넣어둔 오브젝트가 지워지거나 어디다 뒀는지 잃어버렸다면? 혹은 다른 씬이나 타 스크립트에서 해당 정보에 접근해야한다면?
대부분의 경우 '싱글톤'을 많이 쓴다
하지만 싱글톤은 static클래스와 마찬가지로 단점은 명확하고 정확한 사용 이유가 없다면 되도록 지양해야 하는 부분이다
*싱글톤과 static의 단점
https://jeong-pro.tistory.com/86
https://unityindepth.tistory.com/51
이럴때 사용하는게 Zenject, DI패턴(의존성 주입)이다
의존성 주입에 대한 장점은 아래와같다
1. 유닛테스트의 편의성
2. 코드 재활용
3. *객체간의 의존성을 줄일수있음
https://velog.io/@wlsdud2194/what-is-di
즉, 처음 본 예제때 처럼 '오브젝트'에 붙어있는 '스크립트'에 강제로 연결해야되고
항상 해당 '오브젝트'에서 '스크립트'를 가져와서 써야되는, '객체에 의존적'인 상황을 줄일수있다
그럼 구현을 해보자
해당 에셋은 에셋스토어에서 받을수있다
가볍게 임포트로 시작
Zenject옵션을 이용해서 프로젝트에 intaller를 생성한다

사진 설명을 입력하세요.
해당 스크립트가 의존성을 '주입'해준다고 보면된다
이제 아까 사용했던 'User' 스크립트를 '객체화'해서 진행한다

사진 설명을 입력하세요.
스크립트를 만들어준다음
public interface IUser
{
string Name { get; set; }
string Age { get; set; }
string Nation { get; set; }
}
인터페이스 하나 만들고
해당 인터페이스를 상속해서 User를 갱신한다
public class User : IUser
{
public string Name { get; set; }
public string Age { get; set; }
public string Nation { get; set; }
public User()
{
Name = "테스터";
Age = "20세";
Nation = "KOR";
}
}
(생성자도 추가해줌)
그다음 해당 인터페이스와 클래스를 '바인딩'해준다
바인딩하는 방법은 아까 installer에서 선언해준다
public class ServiceInstaller : MonoInstaller
{
public override void InstallBindings()
{
Container.Bind<IUser>().To<User>().AsSingle();
}
}
그리고 씬에 'SceneContext'를 추가한다

사진 설명을 입력하세요.
생성된 Scene Context에 MonoInstaller를 넣어준다

사진 설명을 입력하세요.
이러면 끝
그럼 본격적으로 사용해보자
아까 Information스크립트에서 사용하자
using Zenject;
Zenject를 추가한다음
private IUser m_user;
[Inject]
public void Construct(IUser user)
{
m_user = user;
}
Iuser를 Inject하고, 변수에 할당해준다
private void Start()
{
m_userName.text = m_user.Name;
m_userAge.text = m_user.Age;
m_userNation.text = m_user.Nation;
}
그러면 이렇게 변수를 활용해서 바로 사용할수있다

사진 설명을 입력하세요.
"어? 그러면 그냥 변수하나 만들어서 객체로 끌어당기는거랑 뭐가다르지?"
바로 응용해보자

사진 설명을 입력하세요.
새로운 스크립트를 만든다
public class TestUser : IUser
{
public string Name { get; set; }
public string Age { get; set; }
public string Nation { get; set; }
public TestUser()
{
Name = "테스트 유저";
Age = "999세";
Nation = "JPN";
}
}
User스크립트와 똑같이 IUser를 상속하는, User 다른 스크립트다
그리고 이제..
public class ServiceInstaller : MonoInstaller
{
public override void InstallBindings()
{
//Container.Bind<IUser>().To<User>().AsSingle();
//->
Container.Bind<IUser>().To<TestUser>().AsSingle();
}
}
의존성을 바꿔준다
(User에서 TestUser로)

사진 설명을 입력하세요.
즉, 기존 코드는 그대로인 상태에서
어떤걸 Bind해줬는지에 따라서 취급이 달라진다
이렇게 실제 구현부분과, 객체 부분을 '완전히' 분리한다면
두 부분은 서로 엮여있지 않아서 각각 개별적으로 수정, 교체 등을 할수있다
실전 응용 예시)
IInfomationSceneService infomationSceneService = null;
if (EditorData.Instance.CurrentBuildType == EditorData.BUILD_TYPE.A)
infomationSceneService = new AInfomationScene();
else if EditorData.Instance.CurrentBuildType == EditorData.BUILD_TYPE.B)
infomationSceneService = new BInfomationScene();
else
infomationSceneService = new CInfomationScene();
Container.Bind<IInfomationSceneService>().FromInstance(infomationSceneService).AsSingle();
1. IInfomationSceneService 인터페이스 함수, infomationSceneService 를 선언
2. 에디터에서 수정 가능한 CurrentBuildType 변수의 BUILD_TYPE에 따라서 A, B, C로 구분
3. 각 타입에 맞춰 infomationSceneService가 AInfomationScene() 등 각 함수로 할당
4. 할당된 infomationSceneService를 Bind 진행
위 방식으로 유닛테스트용, 디버그용, 릴리즈용 등으로 구분할수 있다
추가
생성자에 Inject을 추가하면 각각 객체간에 연결도 가능하다
즉..
var databaseService = new DatabaseService();
Container.Bind<IDataBaseService>().FromInstance(dataBaseService).AsSingle();
이렇게 따로 동적생성해서 변수로 할당해둔뒤 Bind한다음
public class DataContainerService : IDataContainerService
{
private IDataBaseService m_dataBaseService;
public DataContainerService(IDataBaseService dataBaseService)
{
m_dataBaseService = dataBaseService;
}
}
특정 클래스에 IDataBaseService 를 생성자로 만들어서 넣어준다음
var dataContainerService = new DataContainerService(databaseService);
Container.Bind<IDataContainerService>().FromInstance(dataContainerService).AsSingle();
이런식으로 DataContainerService에서 databaseService를 넣어주면서 다시 Bind하면
각 객체간에도 연결이 가능하다
'유니티' 카테고리의 다른 글
Instantiate, Delegate, Event - 버튼 이벤트 (0) | 2022.02.15 |
---|---|
ZenJect - 의존성 주입 - Factory (0) | 2022.02.15 |
유니티 무한스크롤 (infinite scrollview) (0) | 2022.02.15 |
JsonUtility 사용법 (0) | 2022.02.15 |
페이드인 이펙트 (0) | 2022.02.15 |