是否有可能真正“密封”一个类函数,使其不能在子类中以任何方式被重写?

问题描述 投票:0回答:1

通过代码解释核心问题:

假设我有一个界面

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 }

	
c# inheritance abstract-class
1个回答
0
投票

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 引用。

© www.soinside.com 2019 - 2024. All rights reserved.