using GFramework.Core.Abstractions.Events; using GFramework.Core.Abstractions.Property; using GFramework.Core.Abstractions.StateManagement; using GFramework.Core.Events; namespace GFramework.Core.StateManagement; /// /// Store 选择结果的只读绑定视图。 /// 该类型将整棵状态树上的订阅转换为局部状态片段的订阅, /// 使现有依赖 IReadonlyBindableProperty 的 UI 代码能够平滑复用到 Store 场景中。 /// /// 源状态类型。 /// 投影后的局部状态类型。 public class StoreSelection : IReadonlyBindableProperty { /// /// 用于判断选择结果是否真正变化的比较器。 /// private readonly IEqualityComparer _comparer; /// /// 当前监听器列表。 /// private readonly List> _listeners = []; /// /// 保护监听器集合和底层 Store 订阅句柄的同步锁。 /// private readonly object _lock = new(); /// /// 负责从完整状态中投影出局部状态的选择器。 /// private readonly Func _selector; /// /// 源 Store。 /// private readonly IReadonlyStore _store; /// /// 当前已缓存的选择结果。 /// 该缓存仅在存在监听器时用于变化比较和事件通知,直接读取 Value 时始终以 Store 当前状态为准。 /// private TSelected _currentValue = default!; /// /// 连接到底层 Store 的订阅句柄。 /// 仅当当前存在至少一个监听器时才会建立该订阅,以减少长期闲置对象造成的引用链。 /// private IUnRegister? _storeSubscription; /// /// 初始化一个新的 Store 选择视图。 /// /// 源 Store。 /// 状态选择器。 /// 选择结果比较器;未提供时使用 。 /// /// 当 时抛出。 /// public StoreSelection( IReadonlyStore store, Func selector, IEqualityComparer? comparer = null) { _store = store ?? throw new ArgumentNullException(nameof(store)); _selector = selector ?? throw new ArgumentNullException(nameof(selector)); _comparer = comparer ?? EqualityComparer.Default; } /// /// 获取当前选择结果。 /// public TSelected Value => _selector(_store.State); /// /// 将无参事件监听适配为带选择结果参数的监听。 /// /// 无参事件监听器。 /// 用于取消订阅的句柄。 IUnRegister IEvent.Register(Action onEvent) { ArgumentNullException.ThrowIfNull(onEvent); return Register(_ => onEvent()); } /// /// 注册选择结果变化监听器。 /// /// 选择结果变化时的回调。 /// 用于取消订阅的句柄。 /// 时抛出。 public IUnRegister Register(Action onValueChanged) { ArgumentNullException.ThrowIfNull(onValueChanged); var shouldAttach = false; lock (_lock) { if (_listeners.Count == 0) { _currentValue = Value; shouldAttach = true; } _listeners.Add(onValueChanged); } if (shouldAttach) { AttachToStore(); } return new DefaultUnRegister(() => UnRegister(onValueChanged)); } /// /// 注册选择结果变化监听器,并立即回放当前值。 /// /// 选择结果变化时的回调。 /// 用于取消订阅的句柄。 /// 时抛出。 public IUnRegister RegisterWithInitValue(Action action) { ArgumentNullException.ThrowIfNull(action); var currentValue = Value; action(currentValue); return Register(action); } /// /// 取消注册选择结果变化监听器。 /// /// 需要移除的监听器。 /// 时抛出。 public void UnRegister(Action onValueChanged) { ArgumentNullException.ThrowIfNull(onValueChanged); IUnRegister? storeSubscription = null; lock (_lock) { _listeners.Remove(onValueChanged); if (_listeners.Count == 0 && _storeSubscription != null) { storeSubscription = _storeSubscription; _storeSubscription = null; } } storeSubscription?.UnRegister(); } /// /// 将当前选择视图连接到底层 Store。 /// private void AttachToStore() { var subscription = _store.Subscribe(OnStoreChanged); Action[] listenersSnapshot = Array.Empty>(); var latestValue = Value; var shouldNotify = false; lock (_lock) { // 如果在建立底层订阅期间所有监听器都已被移除,则立即释放刚刚建立的订阅, // 避免选择视图在无人监听时继续被 Store 保持引用。 if (_listeners.Count == 0) { subscription.UnRegister(); return; } if (_storeSubscription != null) { subscription.UnRegister(); return; } _storeSubscription = subscription; if (!_comparer.Equals(_currentValue, latestValue)) { _currentValue = latestValue; listenersSnapshot = _listeners.ToArray(); shouldNotify = listenersSnapshot.Length > 0; } } if (!shouldNotify) { return; } foreach (var listener in listenersSnapshot) { listener(latestValue); } } /// /// 响应底层 Store 的状态变化,并在选中片段真正变化时通知监听器。 /// /// 新的完整状态。 private void OnStoreChanged(TState state) { var selectedValue = _selector(state); Action[] listenersSnapshot = Array.Empty>(); lock (_lock) { if (_listeners.Count == 0 || _comparer.Equals(_currentValue, selectedValue)) { return; } _currentValue = selectedValue; listenersSnapshot = _listeners.ToArray(); } foreach (var listener in listenersSnapshot) { listener(selectedValue); } } }