You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何临时排除指定通知渠道?C#通知系统优化需求

Solution for Temporary Channel Exclusion in C# Notification System

Great question! Let's tackle this while keeping solid OOP principles intact—specifically avoiding tight coupling between your Runner class and concrete channel types like MailNotificationChannel. The key is to lean into abstraction and let your NotificationChannelEngine handle the filtering logic, so Runner never needs to reference specific channel implementations.

Core Approach: Temporary Filter Rules in the Engine

Instead of modifying the Process method with parameters or adding Suppress/Resume that depend on concrete types, we'll extend the engine to support temporary, rule-based channel filtering. Here's how it works:

  1. Add a unique identifier to the INotificationChannel abstraction (so we can target channels without knowing their concrete type)
  2. Update the engine to manage temporary filter functions
  3. Let Runner add/remove filters using the abstract identifier, never touching concrete channel classes

Step 1: Extend the INotificationChannel Abstraction

Add a ChannelId property to uniquely identify each channel without exposing its concrete type:

public interface INotificationChannel
{
    // Unique identifier for the channel (e.g., "Mail", "FileLog", "Console")
    string ChannelId { get; }
    void SendNotification(string message);
}

Implement this in your concrete channels (example for Mail):

public class MailNotificationChannel : INotificationChannel
{
    public string ChannelId => "Mail";

    public void SendNotification(string message)
    {
        // Existing mail sending logic
    }
}

Step 2: Update NotificationChannelEngine to Support Temporary Filters

Modify the engine to track temporary filters and apply them when processing notifications:

public class NotificationChannelEngine
{
    private readonly List<INotificationChannel> _registeredChannels = new();
    private readonly Dictionary<Guid, Func<INotificationChannel, bool>> _temporaryFilters = new();

    public void RegisterChannel(INotificationChannel channel)
    {
        _registeredChannels.Add(channel);
    }

    // Adds a temporary filter and returns an ID to later remove it
    public Guid AddTemporaryFilter(Func<INotificationChannel, bool> filterRule)
    {
        var filterId = Guid.NewGuid();
        _temporaryFilters.Add(filterId, filterRule);
        return filterId;
    }

    // Removes a specific temporary filter using its ID
    public bool RemoveTemporaryFilter(Guid filterId)
    {
        return _temporaryFilters.Remove(filterId);
    }

    public void Process(string message)
    {
        // Only process channels that pass ALL temporary filters
        var eligibleChannels = _registeredChannels
            .Where(channel => _temporaryFilters.Values.All(filter => filter(channel)));

        foreach (var channel in eligibleChannels)
        {
            channel.SendNotification(message);
        }
    }
}

Step 3: Update Runner to Use Filters (No Concrete Dependencies)

Now your Runner can temporarily exclude the mail channel without ever referencing MailNotificationChannel:

public class Runner
{
    private readonly NotificationChannelEngine _notificationEngine;
    private Guid? _mailExclusionFilterId;

    public Runner(NotificationChannelEngine notificationEngine)
    {
        _notificationEngine = notificationEngine;
    }

    public void Operation3()
    {
        // Add a filter to exclude the "Mail" channel
        _mailExclusionFilterId = _notificationEngine.AddTemporaryFilter(
            channel => channel.ChannelId != "Mail"
        );

        // Process notification—mail will be skipped
        _notificationEngine.Process("Operation 3: Critical update (no mail)");
    }

    public void Operation4()
    {
        // Remove the filter to restore mail notifications
        if (_mailExclusionFilterId.HasValue)
        {
            _notificationEngine.RemoveTemporaryFilter(_mailExclusionFilterId.Value);
            _mailExclusionFilterId = null;
        }

        // Process notification—mail is now included again
        _notificationEngine.Process("Operation 4: Update complete (mail restored)");
    }
}

Why This Follows OOP Principles

  • Dependency Inversion Principle: Runner only depends on abstractions (INotificationChannel, NotificationChannelEngine)—no concrete channel types are referenced.
  • Open/Closed Principle: Adding new channel exclusion rules doesn't require modifying existing engine or runner code.
  • Single Responsibility Principle: The engine handles channel management and filtering, while Runner focuses on business operations.
  • Flexibility: You can easily extend this to exclude multiple channels, or add more complex filter rules (e.g., exclude based on channel priority) without breaking existing code.

内容的提问来源于stack exchange,提问作者Arie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:26:59