类似于带有定义的抽象c#
本文关键字:抽象 定义 类似于 | 更新日期: 2023-09-27 18:10:58
也许这是一个糟糕的设计,但我有一个抽象基类,它有一个方法validate
public abstract class abClass{
string str1;
string str2;
public virtual bool validate(){...};
}
我知道每个派生类都有需要验证的属性,但我不想为每个抽象方法复制粘贴str1
和str2
的验证。
我想确保未来的开发人员(包括我自己)会记得包含并填写一个验证方法。从我所看到的来看,没有办法给抽象方法一个定义,或者强制一个虚方法被重写。
到目前为止,我听到的所有关于这一点的说法都是"你应该让开发人员选择他/她想做什么。"这对我来说还不够好,它违背了帮助你不犯错误的制衡。如果他们主动选择不包含任何实现代码,我并不介意,但如果他们忘记了,那么当派生字段没有得到验证时,就会引起头痛。对于这个问题有什么建议吗?你可以使用Template方法模式:
public bool Validate()
{
// Call base class validation
if (!ValidateCore())
return false;
// Call specific validation code (overridden by derived classes)
return ValidateOverride();
}
private bool ValidateCore()
{
// Validate str1 and str2
// ...
}
protected abstract bool ValidateOverride();
这样,派生类必须覆盖ValidateOverride
(因为它是抽象的),并且它们不能忘记调用ValidateCore
,因为它是由基类中的非虚拟方法调用的。
Martin Fowler在他的CallSuper文章中讨论过这个问题。
他基本上指出,要求类的子类在重写时调用基类方法是一个不好的实践或反模式:
Call Super是在OO框架中不时出现的一种轻微的气味(如果您喜欢,也可以称为反模式)。它的症状很容易发现。为了插入某个框架,您正在继承超类。文档中有类似这样的内容:"要做自己的事情,只需创建进程方法的子类。然而,重要的是要记住在开始你的方法时调用超类"
他提出的解决方案是基类应该负责自己需要做的事情,而让派生类只关心派生类的关注点:
相反,API应该为您记住内务管理调用。通常的方法是使句柄方法成为模板方法,如下所示:
//translation of java code to proper C#
public abstract class EventHandler ...
{
public void Handle (BankingEvent e)
{
HouseKeeping(e); //this is required by the base class.
DoHandle(e); //Here, control is delegated to the abstract method.
}
protected abstract void DoHandle(BankingEvent e);
}
public class TransferEventHandler: EventHandler
{
protected override void DoHandle(BankingEvent e)
{
initiateTransfer(e);
}
}
你可以这样做:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication6
{
class Program
{
static void Main(string[] args)
{
Base good = new Good();
Base bad = new Bad();
good.Validate();
bad.Validate(); // This blows up
Console.ReadLine();
}
}
public class Base
{
public virtual void Validate()
{
throw new NotImplementedException();
}
}
public class Good : Base
{
public override void Validate()
{
Console.WriteLine("Looks good to me.");
}
}
public class Bad : Base
{
}
}
…虽然如果由我来决定,我只会用Validate()方法定义一个接口。