【问题标题】:Alternative to Template Pattern where the implementation can have an attribute实现可以具有属性的模板模式的替代方案
【发布时间】:2022-08-06 11:39:38
【问题描述】:

我正在使用一系列代表不同类型事件的模板模式类。

internal abstract class DayEndingEvent : Event
{  
    internal void OnDayEnding(object? sender, DayEndingEventArgs e)
    {
        if (IsHooked) OnDayEndingImpl(sender, e);
    }

    protected abstract void OnDayEndingImpl(object? sender, DayEndingEventArgs e);
}

此模式确保实现仅在事件被“挂钩”时运行,这允许应用程序的其他部分通过调用基类 Event 中的 HookUnhook 方法来激活/停用事件。

internal abstract class Event
{
    public bool IsHooked {get; private set;}

    public bool Hook() => !IsHooked && (IsHooked = true);

    public bool Unhook() => IsHooked && !(IsHooked = false);
}

Event 显然比这更复杂,但这足以得到图片)。 我的EventManager 可以实例化此模式的每个实现之一,并将它们的OnDayEnding 挂钩到外部API 中的适当处理程序。

这已经有一段时间了,但现在我有一个新的要求来为这些类添加优先级。这样做的唯一方法(这是外部 API 的限制)是将属性 [EventPriority] 添加到事件回调中。但显然我不能用优先级注释OnDayEnding,因为这会设置优先级全部实现,这违背了整个目的。

除了回调,该属性在其他任何地方都没有影响。我能看到的唯一其他解决方案是删除 Impl 并使回调本身抽象。但这意味着我必须在每个实现上手动检查IsHooked 标志,这是我想要避免的。

所以问题是,任何人都可以提出这种模式的替代方案,它既可以 1)允许我有不同的回调实现,我可以向其中添加优先级属性,以及 2)强制检查 IsHooked

    标签: c# inheritance events attributes


    【解决方案1】:

    最近遇到类似问题的时候想到了两种可能:

    选项一,有一个具有所需属性的入口方法:

    public class SpecificImplementationClass1 : BaseClass, IInitializer 
    {
        [SomeAttribute]
        public void CallMeToInitiate(SomeType input)
        {
            ExecuteCommonCode(input);
        }
    
        protected override void ExecuteSpecificCode(object input)
        {
            var typedInput = (SomeType) input;
            // ...execute whatever implementation-specific code here
        }
    }
    
    public class BaseClass
    {
        protected void ExecuteCommonCode(object input)
        {
             // DoSomethingBefore(input);
             ExecuteSpecificCode(input);
             // DoSomethingAfter(input);
        }
    
        protected abstract void ExecuteSpecificCode(object input);
    }
    
    public interface IInitializer
    {
        void CallMeToInitialize(SomeType input);
    }
    
    // Get all IInterface through dependency injection and call "CallMeToInitialize(new SomeType())" on each
    

    选项二,使用template delegate pattern

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-29
      • 2013-05-02
      • 2011-04-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多