通过代码解释核心问题:
假设我有一个界面
public interface IWorker
{
void DoWork();
}
现在,设置一个实现该接口的抽象类。我希望这个抽象类的
DoWork()
函数逻辑成为该函数唯一可能的实现。此抽象类的子类不应该能够覆盖该功能。相反,他们被迫提供一些“辅助”功能来帮助 DoWork()
实现:
public abstract class AbstractWorker : IWorker
{
// I cannot force this to be "sealed" - sealed keyword cannot be applied. All subclass's
// could override this logic if they wanted to
public void DoWork()
{
if (ShouldProcess()) Process();
}
public abstract bool ShouldProcess();
public abstract void Process();
}
public class Worker : AbstractWorker
{
// I DON'T want this to be possible - overriding this implementation.
// I want forced usage of the abstract class implementation.
public new void DoWork()
{
// Look at me, I'm going to decide to deviate away from my base class implementation
}
public override bool ShouldProcess() => true;
public override void Process() => Console.WriteLine("Processed");
}
// Consumer code
public void SomeFunction()
{
IWorker worker = GetWorkerSomehow();
// I want this to always use the abstract class implementation
// regardless of what concrete class I get back here.
worker.DoWork();
}
我希望对具有接口
IWorker
的对象的任何调用始终使用抽象类实现中的逻辑,而不是通过子类必须实现的抽象函数来委托实际处理。如果子类决定覆盖 DoWork()
类,似乎没有办法导致编译错误。他们始终能够通过函数签名上的 new
运算符来执行此操作。
现实世界的例子,因为我知道人们可能会说我正在尝试做一些意想不到的事情,应该寻找不同的实施策略(也许我就是这样)。我正在寻求实现“责任链”设计模式。该模式具有抽象类用法,具体类实现该抽象类用法以使该模式发挥作用。这些具体类应该决定处理请求,或者如果不能,则调用下一个请求处理程序。但这个想法没有得到执行。有人可能会创建一个新的具体类,却忘记将调用转发给下一个处理程序,从而破坏链。我想要强制保证所有具体类中始终遵循该模式。
代码:
public interface IHandler
{
void HandleRequest();
IHandler SetNextHandler(IHandler nextHandler);
}
public abstract class AbstractHandler : IHandler
{
private readonly IHandler _nextHandler;
public IHandler SetNextHandler(IHandler nextHandler);
{
_nextHandler = nextHandler;
return nextHandler;
}
// Forced calling of the _nextHandler if applicable
public void HandleRequest()
{
if (CanHandleRequest()) ProcessRequest();
else if (_nextHandler is not null) _nextHandler.HandleRequest();
}
// Forced function implementations on the concrete classes
// that aids in the HandleRequest() process
public abstract bool CanHandleRequest();
public abstract void ProcessRequest();
}
public class GoodHandler : AbstractHandler
{
public override bool CanHandleRequest() => true;
public override void ProcessRequest() { // Do stuff }
}
public class BadHandler : AbstractHandler
{
// Don't want this override via the 'new' keyword to be possible....should only use
// the abstract class implementation
public new void HandleRequest()
{
if (CanHandleRequest()) ProcessRequest();
// Look, I don't decide to forward the request to nextHandler, chain is broken
// I must rely on future class creators to fully understand this concept.
}
public override bool CanHandleRequest() => false;
public override void ProcessRequest() { // Do stuff }
}
// Consumer code
public void SomeFunction()
{
IHandler good = new GoodHandler();
IHandler bad = new BadHandler();
bad.SetNextHandler(good);
bad.HandleRequest(); // We will never call to the "good" handler
}
public abstract class AbstractHandler
{
private AbstractHandler? _nextHandler;
public AbstractHandler SetNextHandler(AbstracHandler nextHandler);
{
_nextHandler = nextHandler;
return nextHandler;
}
// Forced calling of the _nextHandler if applicable
public void HandleRequest()
{
if (CanHandleRequest()) ProcessRequest();
else if (_nextHandler is not null) _nextHandler.HandleRequest();
}
// Forced function implementations on the concrete classes
// that aids in the HandleRequest() process
public abstract bool CanHandleRequest();
public abstract void ProcessRequest();
}
现在所有处理程序都必须符合并使用基类方法。
接口的使用允许覆盖。例如,在您的示例中,我可以:
public class BadHandler : IHandler
{
// ...
}
您在扩展 AbstractHandler 的类上的 AddHandler 也不会更明智。对 HandleRequest 的调用将移交给一些自定义实现,并可能破坏链条。
仅使用基本抽象类,即使我重载了 HandleRequest 方法:
public class BadHandler : AbstractHandler
{
public new void HandleRequest()
{
throw new Exception("Hell no, I ain't going to play nice!");
}
}
...没关系,它不会作为 HandleRequest 链的一部分被调用。调用它的唯一方法是使用具体的 BadHandler 引用。