Observer 패턴을 활용한 리액티브 프로퍼티 및 컬렉션은 데이터의 변화를 감지하고 이를 구독자에게 알리는 역할을 한다. 이를 통해 UI나 데이터 로직이 변화에 반응하도록 설계할 수 있으며, 특히 VIPER 패턴의 Interactor와 잘 어울리는 구조를 형성할 수 있다. 이번 글에서는 C#을 기반으로 구현한 ReactiveProperty<T>, ReactiveList<T>, ReactiveDictionary<K, V>, ReactiveArray<T> 클래스에 대해 설명한다.
1. 리액티브 프로퍼티
ReactiveProperty<T>는 단일 값의 변경을 감지하고 이를 구독자에게 전달하는 역할을 한다. 내부적으로 onChanged 델리게이트를 사용하여 값이 변경될 때만 이벤트를 발생시키도록 설계되었다.
public class ReactiveProperty<T>
{
private T value;
private Action<T> onChanged;
public ReactiveProperty(T initialValue, Action<T> onChanged = null)
{
this.value = initialValue;
this.onChanged = onChanged;
}
public T Value
{
get => value;
set
{
if (!Equals(this.value, value))
{
this.value = value;
onChanged?.Invoke(value);
}
}
}
public void AddListener(Action<T> callback)
{
onChanged += callback;
}
public void RemoveListener(Action<T> callback)
{
onChanged -= callback;
}
}
위의 클래스는 값을 저장하고 Value 프로퍼티를 통해 접근할 수 있도록 한다. 값이 변경되었을 때만 onChanged 이벤트를 호출하여 불필요한 이벤트 호출을 방지한다.
2. 리액티브 리스트
ReactiveList<T>는 List<T>를 감싸는 형태로, 요소가 추가되거나 삭제될 때 OnChanged 이벤트를 호출하도록 설계되었다.
public class ReactiveList<T> : IList<T>
{
private readonly List<T> _list = new List<T>();
public Action OnChanged;
public T this[int index]
{
get => _list[index];
set
{
_list[index] = value;
OnChanged?.Invoke();
}
}
public void Add(T item)
{
_list.Add(item);
OnChanged?.Invoke();
}
public bool Remove(T item)
{
bool removed = _list.Remove(item);
if (removed) OnChanged?.Invoke();
return removed;
}
}
위 클래스에서는 List<T>의 기본적인 기능을 유지하면서도 요소가 추가, 삭제될 때 OnChanged 이벤트를 호출하여 변경 사항을 감지할 수 있도록 하였다.
3. 리액티브 딕셔너리
ReactiveDictionary<K, V>는 키-값 데이터를 저장하는 Dictionary<K, V>를 감싸는 구조로, 값이 변경될 때 OnChanged 이벤트를 호출하도록 구현되었다.
public class ReactiveDictionary<K, V> : IDictionary<K, V>
{
private readonly Dictionary<K, V> _dictionary = new Dictionary<K, V>();
public Action OnChanged;
public V this[K key]
{
get => _dictionary[key];
set
{
_dictionary[key] = value;
OnChanged?.Invoke();
}
}
public void Add(K key, V value)
{
_dictionary.Add(key, value);
OnChanged?.Invoke();
}
public bool Remove(K key)
{
bool removed = _dictionary.Remove(key);
if (removed) OnChanged?.Invoke();
return removed;
}
}
이 클래스는 기존 Dictionary<K, V>의 기능을 유지하면서 값이 변경될 때 이벤트를 발생시킨다. 이를 통해 데이터 변경을 실시간으로 감지하고 UI 등에 반영할 수 있다.
4. 리액티브 배열
배열은 크기가 고정되는 특성이 있으므로 Resize 기능을 추가하여 크기를 동적으로 조정할 수 있도록 하였다.
public class ReactiveArray<T> : IEnumerable<T>
{
private T[] _array;
public Action OnChanged;
public int Length => _array.Length;
public ReactiveArray(int size)
{
_array = new T[size];
}
public T this[int index]
{
get => _array[index];
set
{
_array[index] = value;
OnChanged?.Invoke();
}
}
public void Resize(int newSize)
{
int oldSize = _array.Length;
Array.Resize(ref _array, newSize);
T defaultValue = default;
for (int i = oldSize; i < newSize; i++)
{
_array[i] = defaultValue;
}
OnChanged?.Invoke();
}
}
위 클래스는 배열의 요소 변경을 감지할 수 있도록 하며, Resize 메서드를 통해 동적으로 크기를 조절할 수 있도록 하였다
Observer 패턴을 활용한 ReactiveProperty 및 ReactiveCollections은 데이터의 변화를 감지하고 이를 실시간으로 반영하는 데 유용하게 사용할 수 있다. 특히, VIPER 패턴에서 Interactor와 잘 결합하여 데이터 상태 변화를 효과적으로 관리할 수 있다. 이번 구현에서는 List<T>, Dictionary<K, V>, Array 등을 래핑하여 이벤트 기반으로 동작하도록 만들었으며, 향후 성능 최적화 및 비동기 환경에서의 활용 가능성을 고려할 필요가 있다.
'소프트웨어 공학 > 코딩' 카테고리의 다른 글
| Utility AI (0) | 2025.04.06 |
|---|---|
| 클래스 관계의 종류와 객체지향 설계에서의 활용 (0) | 2025.03.17 |
| C#,유니티] 제네릭과 상속을 함께 사용하는 방법 (0) | 2025.03.11 |
| C#] 자식 클래스인지 판별하고 사용하는 방법들 (0) | 2025.03.10 |
| 유니티] Attribute [RequireComponent(typeof())] 개요 및 활용법 (0) | 2025.03.07 |