Coding Memo
Observer Pattern [관찰자 패턴] 본문
Observer 패턴은 Observable 패턴으로 불리기도 한다.
Observer 패턴은 개체 간 1:N 종속성을 설정할 때 사용되는 동작(행태) 디자인 패턴이다.
Subject의 상태가 변경되면 이 Subject에 등록되어 있는 Observer들에게 통지를 해주어 Observer에서 각각의 처리를 할 수 있도록 알려준다.
개제 간에 느슨한 결합을 형성하며, 몇몇 언어들을 자체적으로 간접적 제공(인터페이스 및 클래스)하는 경우도 있다.
예시
C# | System - IObservable<T>, IObserver<T> |
Java | java.util.Observable, java.util.Observer |
Note: 관찰자 패턴은 UI를 업데이트하는데에도 이용할 수 있다. 특정 값이 변경되었을 때, 변화를 감지하고 UI를 자동으로 업데이트 하도록 할 수도 있다!
관찰자 패턴
Subject | 상태를 유지하고 관찰자에게 알림을 보내는 객체로, 관찰자를 등록, 등록 취소 및 통지의 기능을 포함 |
Observer | Subject가 상태가 변경될 때 알림을 받고자 하는 객체 |
Register | Observer는 알림을 받을 대상에 자신을 등록 (Subscribe, AddObserver ...) |
Notification | Subject의 상태가 변경되면 등록된 모든 Observer에게 알리고 등록된 각 Observer는 Notify를 통해 특정 메소드를 각각 수행하여 상태 변경과 관련된 작업을 처리 |
Subject의 상태를 관찰할 Observer들을 등록(추가)하고, Subject의 상태가 변경될 때, 등록된 모든 Observer에게 통지를 해주어 Notify 함수를 호출하도록 한다.
UML
NOTE: Subject와 Observer를 인터페이스로 구현할지, 추상 클래스로 구현할지는 적용할 애플리케이션에 맞게 잘 생각하여 사용하자.
구현 (Example)
기본적인 인터페이스를 상속한 클래스의 코드는 다음과 같을 것이다.
public interface IObserver
{
public void Notify();
}
public interface ISubject
{
public void AddObserver(IObserver observer);
public void RemoveObserver(IObserver observer);
public void NotifyObservers();
}
public class ConcreateSubject : ISubject
{
List<IObserver> _observers = new();
public void AddObserver(IObserver observer)
{
_observers.Add(observer);
}
public void NotifyObservers()
{
foreach (var observer in _observers)
{
observer.Notify();
}
}
public void RemoveObserver(IObserver observer)
{
_observers.Remove(observer);
}
}
public class ConcreateObserver : IObserver
{
public void Notify()
{
// TODO
}
}
이를 이용해 샘플 코드를 작성하여 사용법을 알아보자.
Subject
public class ConcreateSubject : ISubject
{
public int N { get; private set; } = 0;
List<IObserver> _observers = new();
public void AddN(int dvalue)
{
N += dvalue;
NotifyObservers();
}
public void AddObserver(IObserver observer)
{
_observers.Add(observer);
}
public void NotifyObservers()
{
foreach (var observer in _observers)
{
observer.Notify();
}
}
public void RemoveObserver(IObserver observer)
{
_observers.Remove(observer);
}
public override string ToString()
{
return $"N={N}";
}
}
Observer
public class ConcreateObserver : IObserver
{
ISubject _subject;
public ConcreateObserver(ISubject subject)
{
_subject = subject;
//subject.AddObserver(this); // 여기서 자동으로 등록해줄 수도 있다.
}
public void Notify()
{
Console.WriteLine($"This is observer... notified from subject: {_subject}");
}
}
Main
public static void Main()
{
ConcreateSubject subject = new();
ConcreateObserver observer1 = new(subject);
ConcreateObserver observer2 = new(subject);
subject.AddObserver(observer1);
subject.AddObserver(observer2);
subject.AddN(10);
}
N값을 변화 시켰을 때 등록된 관찰자들에게 Notify를 한다. (여기서는 AddN이라는 함수를 통해 N 값을 수정했다.)
출력 결과
관찰자 패턴의 장단점
관찰자 패턴도 여러가지 면에서 장점과 단점이 존재한다.
Pros | Cons |
- Loose Coupling - Extensibility - Event-Driven - Maintainability |
- Unintended Updates - Ordering of Notifications - Performance Impact - Debugging Complexity |
장점
- Loose Coupling
Subject는 Observer의 구체적인 내용을 알 필요가 없고, Observer는 Subject와 밀접하게 연결되어 있지 않을 수 있다. 즉, 하나의 구성요소를 변경해도 다른 구성요소에 크게 영향을 미치지 않는 유연한 설계가 가능해진다. - Extensibility
Subject를 수정하지 않고 새로운 Observer를 쉽게 추가할 수 있고 기존 Observer에 영향을 주지 않고 새로운 Subject를 만들 수 있다. (확장성이 좋다.) - Event-Driven
Subject에서 특정 이벤트 또는 상태 변경이 발생하면 Observer에게 자동으로 알리는 이벤트 기반 방식을 사용한다. 이를 통해 개체 간 실시간 업데이트 및 동기화가 가능하다. - Maintainability
Subject와 Observer가 분리되어 있으므로 개별 구성 요소를 수정하거나 테스트하기가 쉬워진다. 한 부분을 변경해도 다름 부분에 파급 효과가 발생할 가능성이 적다. (유지보수에 용이)
단점
- Unintended Updates
어떤 경우에는 기대하지 않았던 업데이트를 받을 수 있다. 즉, 불필요한 처리가 발생할 수도 있기 때문에 필요한 경우에만 업데이트 되도록 설계를 잘 해야된다. - Ordering of Notifications
명시적으로 지정하지 않는 한, Notify하는 순서는 보장되지 않는다. 신중하게 관리해야 되는 Observer 간에 복잡성이나 순서 종속성을 유발할 수도 있다. - Performance Impact
추가적인 객체간 통신 및 알림 메커니즘으로 약간의 성능 오버헤드가 발생할 수 있다. 다수의 Observer가 등록되어 있거나 상태 변화가 잦은 경우 성능에 영향을 끼칠 수 있다. - Debugging Complexity
많은 Observer와 복잡한 종속성이 있는 시스템에서 Observer Pattern는 시스템 흐름을 복잡하게 보일 수 있게 하여 디버깅하기가 어려워 질 수 있다.
Summary
몇몇 언어는 관찰자 패턴을 구현하기 위한 인터페이스나 클래스를 제공하지만 사용자가 원하는 방향대로 프로그래밍하기 위해서는 직접 구현해햐 할때도 많다. 1:N (일대다) 관계가 어떤 시점에서 어떻게 활용되야 할지 고민하고 패턴을 적절히 사용하도록 하자.
'etc' 카테고리의 다른 글
Event Bus Pattern [이벤트 버스 패턴] (0) | 2023.06.18 |
---|---|
Command Pattern [커맨드 패턴] (0) | 2023.06.18 |
Singleton Design Pattern [싱글턴 패턴] (0) | 2023.06.11 |
OSI, TCP/IP (0) | 2023.06.04 |
우분투에서 파일 다운로드: wget (0) | 2022.08.16 |