当目标已经实现一个时实现抽象类

时间:2015-10-08 09:41:51

标签: c# interface abstract-class

我的一些类具有相同的错误存储代码。是两个错误属性(数字和消息)和几种设置错误状态的方法。这段代码在每个类上重复,所以今天我决定重构公共代码并将其解压缩以便重用。

首先我尝试将其创建为界面,但我可以使其工作。在我的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

相同的两个属性和方法。

答案超出了范围,因为建议的解决方案将属性与A和B的调用者隔离开来。它们的实际用途正好传递给调用者一些信息。不做一些外部可重复使用的动作。

5 个答案:

答案 0 :(得分:2)

有一种称为"Composition over inheritance"(或“复合重用原则”)的常见做法。这意味着您将转变为“有一个”关系,而不是“是一个”关系。

在这种情况下,这意味着您将拥有一个处理常见错误的专用类,如下所示:

Home

现在,每个类都通过它的构造函数将其作为参数,并且可以在内部使用它来进行错误处理,这意味着在需要时委托工作:

public inteface IErrorHandler
{
    void HandleError(string errorMessage);
}

public class ErrorHandler : IErrorHandler
{
    public void HandleError(string errorMessage)
    {
        Console.WriteLine(errorMessage);
    }
}

答案 1 :(得分:1)

使用合成而不是继承。将您的错误管理代码移动到一个单独的类,并在需要它的类中保留该类的实例。

答案 2 :(得分:0)

你确定在你的DBEngine定义中每个DBEngine都是相同的ErrorManager,或者你能想到将来你想要创建一个使用不同管理器的DBEngine的子类,甚至是一个类的可能性吗? DBEngine除了ErrorManager以外的各种方式?

人们倾向于继承而不是写作,因为它更少打字。他们忘记了未来的变化会更成问题。

继承上面的组合的优点是,您可以决定让您的班级使用不同的错误处理程序,而您班级的所有百万用户(嘿,您制作完全可用的课程!)不必看到任何来自这种变化的东西。

组合的另一个优点是您可以控制类的用户可以使用错误处理程序的哪些功能。您确定您的类的用户可以使用ErrorManager的任何功能而不会干扰您的DBEngine类吗?

确实组合的缺点是你必须做一些打字。但通常这只是对错误管理器的相应功能的调用。

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();
    }

请注意,您不必重新编码所有困难代码,只需调用处理程序即可。

另请注意,如果要更改引擎类,使用类NotSoGoodErrorHandler:IErrorHanlder,则更改是最小的?

请注意,如果没有大的更改,您可以让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();
    }
}

看到变化很小。如果你的课程不是一个特殊的另类课程,不要使用继承。组合现在可能需要一些额外的打字,但它极大地增加了变化和可重用性的可能性。

答案 3 :(得分:0)

如果你的错误处理是静态的,你可以通过扩展方法来实现:

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

答案 4 :(得分:0)

在班级中创建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!");
    }
}