当目标已经实现抽象类时实现抽象类
本文关键字:实现 抽象类 目标 | 更新日期: 2023-09-27 18:16:38
我的一些类有相同的错误存储代码。是两个错误属性(数字和消息)和几个设置错误状态的方法。这段代码在每个类上重复,所以今天我决定重构公共代码并提取它,以便它可以被重用。
首先我试着把它创建为一个接口,但我可以让它工作。在我的VB.net程序员头脑中,我认为这是移动代码和引用它的简单问题。但是接口不能处理代码。所以我创建了一个抽象类,并开始继承我的其他类。
public class DBEngine : ErrorContainer, IDisposable {
protected DBEngine(string connectionString, string providerName)
public DBEngine(string connectionString = "")
}
但是,当我的一个类已经有继承时,我遇到了一个问题。
public abstract class TypedTable<TRow> : TypedTableBase<TRow> where TRow : TypedRow {
protected TypedTable(SerializationInfo info, StreamingContext context) : base(info, context)
protected TypedTable()
}
如果我继承了接口,它希望我重新实现所有的函数,这对我来说似乎适得其反。
我如何构建我的错误存储代码,以便它可以在我的类上重用,即使它们已经有继承,但避免重写任何代码?
注意:请不要混淆我在这里所说的错误处理。对于错误处理,我使用NLog,并有自己的接口层和静态实现。我在这里说的是重用几个类共有的一些属性,这些属性用来存储错误代码和消息。仅此而已。
ClassA
L public Property1
L public Property2
L private MethodToSet1And2
ClassB : Something (problem there)
L public Property1
L public Property2
L private MethodToSet1And2
相同的两个属性和and方法。
答案超出了范围,因为建议的解决方案将属性与A和b的调用者隔离开来。它们的真正用途是准确地向调用者传递一些信息。
有一种常见的实践称为"组合优于继承"(或"组合重用原则")。这意味着,您将不再使用"是- - -"关系,而是使用"已- - -"关系。
在这种情况下,这意味着你将有一个专门的类来处理常见错误,像这样:
public inteface IErrorHandler
{
void HandleError(string errorMessage);
}
public class ErrorHandler : IErrorHandler
{
public void HandleError(string errorMessage)
{
Console.WriteLine(errorMessage);
}
}
现在,你的每个类都通过它的构造函数将this作为参数,并可以在内部使用它进行错误处理,这意味着你可以在需要的地方将委托给:
public class Foo
{
private readonly IErrorHandler errorHandler;
public Foo(IErrorHandler errorHandler)
{
this.errorHandler = errorHandler;
}
public void DoStuff()
{
// do stuff
errorHandler.HandleError("Everything went wrong!");
}
}
用组合代替继承。将错误管理代码移到一个单独的类中,并在需要它的类中保留该类的实例。
你确定在你的DBEngine定义中,每个DBEngine都是相同的ErrorManager吗?或者你能想到将来你想要创建一个使用不同管理器的DBEngine的子类,甚至是一个除了ErrorManager以外在所有方面都是DBEngine的类吗?
人们倾向于继承而不是撰写,因为它需要更少的输入。他们忘记了未来的变化会更成问题。
复合优于继承的优点是,您可以决定让您的类使用不同的错误处理程序,而您的类的所有百万用户(嘿,您创建了非常可用的类!)不必从这个更改中看到任何东西。
组合的另一个优点是,您可以控制错误处理程序的哪些函数可以被您的类的用户使用。您确定类的用户可以在不干扰DBEngine类的情况下使用ErrorManager的任何函数吗?实际上,组合的缺点是你必须做一些打字工作。但通常这只是对errormanager的相应函数的调用。
interface IErrorHandler
{
void Warning();
void Error();
}
class VeryGoodErrorHandler : IErrorHandler
{
public void Warning()
{
// a lot of difficult code
}
public void Error()
{
// even more difficult code
}
}
class DBEngine : IErrorHandler
{
private IErorHandler myErrorHandler = new VeryGoodErrorHandler()
public void Warning()
{
this.myErrorHandler.Warning();
}
public void Error()
{
this.myErrorHandler.Error();
}
请注意,您不必重新编写所有困难的代码,只需调用处理程序。
还请注意,如果要更改引擎类,则更改是最小的,例如使用类notsogooderorhandler: ierrorhandler ?
请注意,您可以让DBEngine的创建者使用哪个错误处理程序,而无需进行大的更改:
class DBEngine : IErrorHandler
{
private IErorHandler myErrorHandler = null;
public DBEngine()
{ // use default error handler:
myErrorHandler = new VeryGoodErrorHandler();
}
public DBEngine(IErrorHandler userProvidedErrorHandler)
{ // use default error handler:
myErrorHandler = userProvidedErrorHandler
}
public void Warning()
{
this.myErrorHandler.Warning();
}
public void Error()
{
this.myErrorHandler.Error();
}
}
看到的变化是最小的。如果您的类实际上不是另一个类的特殊类型,则不要使用继承。组合现在可能需要一些额外的输入,但它大大增强了更改和可重用性的可能性。
如果你的错误处理是静态的,你可以通过一个扩展方法:
public interface IErrorHandling { }
public static void HandleError(this IErrorHandling errorHandler, string errorMessage)
{
Console.WriteLine(errorMessage);
}
public class YourClass : YourSuperClass, IErrorHandling
{
public void DoSomething()
{
this.HandleError("Error, I did something!");
}
}
如果需要,可以省略this
在你的类中创建ErrorHandler:
public inteface IErrorHandler
{
void HandleError(string errorMessage);
}
public class ErrorHandler : IErrorHandler
{
public void HandleError(string errorMessage)
{
Console.WriteLine(errorMessage);
}
}
public class YourClass: YourSuperClass
{
public IErrorHandler ErrorHandler { get; } = new ErrorHandler();
public void DoSomething()
{
this.ErrorHandler.HandleError("Error, I did something!");
}
}