- 디자인특강(하) 4개의 디자인패턴 정리!
<출처 : 챌린지반 강의노트>
서비스 로케이터 패턴
서비스 로케이터패턴?
- Locate는 찾다라는 의미가 있다. 즉 서비스 로케이터는 서비스들을 로케이터에 등록하여 관리하며 요청하는 쪽에 서비스를 찾아서 건내주는 중간관리자 같은 느낌이다.
- 런타임에 필요한 서비스 객체를 클라이언트에게 제공하는 디자인 패턴, 이 패턴은 애플리케이션에서 서비스 객체를 검색하고 반환하는데 사용한다.(대표적으로 싱글톤)
- 클라이언트 코드가 구체적인 서비스 클래스에 의존하지 않고 간단히 서비스를 찾을 수 있다.
왜 쓰는가
- 모듈화 수준을 높이기 위해 쓴다. 클라이언트와 인터페이스 사이의 의존성을 제거하는 방식으로 모듈화 수준을 높인다. 유연한 코드를 사용하기 위해서는 인터페이스 사용이 필수인데 인터페이스를 자주 사용하게 되면 구현체를 사용하게 되는 번거로움이 생기게 되고 이는 클라이언트 클래스 내부에 구현체를 사용한다면 결국 종속성은 사라지지 않는다. 이를 Composition has a 관계라고 한다.
- 이러한 종속성을 피하기 위해 서비스 로케이터 패턴으로 중앙 레지스트리가 관리하는 서로 다른 인터페이스에 대한 구현체를 저장하고 사용하게 도와준다.
장점과 단점
- 장점 : 클래스의 코드와 서비스 클래스 사이의 결합도가 줄어든다.
- 단점 : 모든 컴포넌트들이 싱글톤 서비스 로케이터에 대한 레퍼런스를 가지고 있어야하고 서비스 로케이터 패턴은 테스트를 하기 힘들고 마지막으로 인터페이스를 쉽게 바꿀 수 있어 문제가 될 수 도 있다.
- 또한 숨겨진 의존성에 대한 문제도 생긴다. 의존성을 구현 내부로 감추게 되면 컴파일타임이 아닌 런타임시에야 문제를 발견할 수 있다. 이것은 결국 내부구현을 이해할 것을 강요한다.
-이러한 문제들을 해결하기 위해 의존성 주입한다. 클라이언트에 필요한 의존성을 동일 클라이언트 내부에서 생성하는것이 아닌 외부에서 set을 해주거나 생성시점에 파라미터로 받아오는 방식으로 보완한다.
예시
using System;
using System.Collections.Generic;
using UnityEngine;
public static class ServiceLocator
{
private static Dictionary<Type, object> services = new Dictionary<Type, object>();
public static void RegisterService<T>(T service) where T : class
{
var type = typeof(T);
if (!services.ContainsKey(type))
{
services.Add(type, service);
}
}
public static T GetService<T>() where T : class
{
var type = typeof(T);
if (services.ContainsKey(type))
{
return (T)services[type];
}
throw new Exception("Service not found: " + type);
}
}
public class AudioService
{
public void PlaySound(string soundName)
{
Debug.Log("Playing sound: " + soundName);
}
}
public class LoggingService
{
public void LogMessage(string message)
{
Debug.Log("Log: " + message);
}
}
public class AudioManager : MonoBehaviour
{
private AudioService audioService;
void Start()
{
audioService = ServiceLocator.GetService<AudioService>();
audioService.PlaySound("BackgroundMusic");
}
}
public class LoggingManager : MonoBehaviour
{
private LoggingService loggingService;
void Start()
{
loggingService = ServiceLocator.GetService<LoggingService>();
loggingService.LogMessage("Game started");
}
}
public class GameInitializer : MonoBehaviour
{
void Awake()
{
AudioService audioService = new AudioService();
LoggingService loggingService = new LoggingService();
ServiceLocator.RegisterService(audioService);
ServiceLocator.RegisterService(loggingService);
}
}
- ServiceLocator클래스에 서비스들을 선언후 모아두고 사용해주기만 하면된다.
데코레이터 패턴
데코레이터패턴?
- 마치 마트료시카와 같다. 다른말로는 Wrapper패턴 으로도 불리는 객체들을 새로운 행동들을 포함한 특수 래퍼 객체들 내에 넣어서 위 행동들을 연결시키는 구조적 디자인 패턴
- 상속을 통해 클래스를 확장한다. 객체를 감싸는 방식으로 기능을 추가하거나 변경
장,단점
- 장점
1.유연한 확장이 가능하다.
2.코드의 재사용성이 높다.
3.단일 책임 원칙을 준수한다.
4.개방폐쇄 원칙을 준수한다.
5.의존성 역전 원칙을 준수한다.
- 단점
1.복잡성이 오히려 증가할수 있다.(과도하게 사용하게 되면 코드를 오히려 이해하기 힘들어진다.)
2.순서 의존성이 생긴다.
3.불필요한 복사가 생긴다.
4.캐시 히트율을 극적으로 떨어드린다.
예시
public interface IComponent
{
void Draw();
}
public class TextBox : IComponent
{
public void Draw()
{
Debug.Log("Drawing TextBox");
}
}
public abstract class ComponentDecorator : IComponent
{
protected IComponent _decoratedComponent;
public ComponentDecorator(IComponent decoratedComponent)
{
_decoratedComponent = decoratedComponent;
}
public virtual void Draw()
{
_decoratedComponent.Draw();
}
}
public class BorderDecorator : ComponentDecorator
{
public BorderDecorator(IComponent decoratedComponent) : base(decoratedComponent) { }
public override void Draw()
{
base.Draw();
DrawBorder();
}
private void DrawBorder()
{
Debug.Log("Drawing Border");
}
}
public class ScrollDecorator : ComponentDecorator
{
public ScrollDecorator(IComponent decoratedComponent) : base(decoratedComponent) { }
public override void Draw()
{
base.Draw();
DrawScrollBar();
}
private void DrawScrollBar()
{
Debug.Log("Drawing ScrollBar");
}
}
public class Window : MonoBehaviour
{
void Start()
{
IComponent textBox = new TextBox();
IComponent borderedTextBox = new BorderDecorator(textBox);
IComponent scrollableBorderedTextBox = new ScrollDecorator(borderedTextBox);
textBox.Draw(); // 출력: Drawing TextBox
borderedTextBox.Draw(); // 출력: Drawing TextBox, Drawing Border
scrollableBorderedTextBox.Draw(); // 출력: Drawing TextBox, Drawing Border, Drawing ScrollBar
}
}
오늘의 회고
- 오늘 특강과 시험이 있어서 팀프로젝트를 많이 못했다. 주말이용해서 좀 해봐야될듯! 그래도 큰틀의 프로토 타입은 완성시켜놓은 상태이니 데이터잘 넣고 아이템 정리만 하면 될것같다.
- 벌써 이번팀프로젝트가 끝나면 2주밖에 남지않았다. 최대한 공부할거 많이 해야겠다. 확실히 코드같은거 보고 이해하는 실력은 많이 늘었는데 뭔가 활용이 어색한거보니 좀 더 코드 많이보고 해봐야겠다.
- 주말동안 너무 놀지 말고 최대한 프로젝트 마무리해야겠다.