抽象类,如何避免代码重复?

时间:2012-02-16 10:28:39

标签: c# inheritance abstract-class

我有以下代码

internal abstract class Base
{
    public DateTime Time;
    public string Message;
    public string Log;
    public abstract void Invoke(string message);
}

internal class SubA : Base
{
    public override void Invoke(string message)
    {
        Time = DateTime.Now;
        // Do A
    }
}

internal class SubB : Base
{
    public override void Invoke(string message)
    {
        Time = DateTime.Now;
        // Do B
    }
}

我有这些从Base类继承的SubA和SubB类,你可以看到我有一个重复自我的代码,它设置了Time,有没有办法将时间设置移动到基类?

6 个答案:

答案 0 :(得分:5)

你可以这样做:

internal abstract class Base
{
    public DateTime Time;
    public string Message;
    public string Log;
    public void Invoke(string message){
         Time = DateTime.Now;
         this.InvokeInternal(message);
    }
    protected abstract void InvokeInternal(string message);
}

internal class SubA : Base
{
    protected override void InvokeInternal(string message)
    {
        // Do A
    }
}

internal class SubB : Base
{
    protected override void InvokeInternal(string message)
    {
        // Do B
    }
}

答案 1 :(得分:3)

有很多可能的解决方案。

这取决于您何时想要设置此属性。

如果您想立即使用它,可以在Base类的构造函数中执行此操作。

internal abstract class Base
{
    public DateTime Time;
    public string Message;
    public string Log;
    public abstract void Invoke(string message);

    public Base()
    {
        Time = DateTime.Now;
    }
}

internal class SubA : Base
{
    public override void Invoke(string message)
    {
        // Do A
    }
}

internal class SubB : Base
{
    public override void Invoke(string message)
    {
        // Do B
    }
}

答案 2 :(得分:2)

改为使用虚拟方法:

internal abstract class Base
{
    public DateTime Time;
    public string Message;
    public string Log;
    public virtual void Invoke(string message) {
        Time = DateTime.Now;
    }
}

internal class SubA : Base
{
}

internal class SubB : Base
{
}

您仍然可以在需要不同实现的子类中覆盖该方法。

答案 3 :(得分:2)

internal abstract class Base
{
    public DateTime Time;
    public string Message;
    public string Log;
    public virtual void Invoke(string message)
    {
        Time = DateTime.Now;
    }

}

internal class SubA : Base
{
    public override void Invoke(string message)
    { 
        base.Invoke(message);
        // Do A
    }
}

internal class SubB : Base
{
    public override void Invoke(string message)
    {
        base.Invoke(message);
        // Do B
    }
}

答案 4 :(得分:0)

已经有很多答案了。作为一种替代方法(以及一些忍者)的方法,我将建议使用方法属性的Lambda表达式。

在你的情况下;

 public class Base
  {
    public DateTime Time;
    public string Message;
    public string Log;
    public Action<string> Invoke { get; set; }

    public Base()
    {
       this.Invoke = InvokeDefault;
    }

    private void InvokeDefault(string message)
    {
       Time = DateTime.Now;
    }
  }

这样,我们为base类提供了默认行为。使用 lambda 表达式,您可以使用不同的Invoke方法创建实例,如下所示。

var myInstance= new Base
  {
    Invoke = () => { Time = DateTime.Now.AddDays(7); }
  };

仅对此Base类的实例重写invoke方法。这提供了更大的灵活性,有助于避免不必要的子类化。

查看此awesome post from Patrick Steele了解详情。

答案 5 :(得分:0)

有两种实用选项,具体取决于您希望代码合同的严格程度。

您可以将逻辑移动到虚拟方法中,并允许子类型在他们选择的情况下重载行为。

internal abstract class Base
{
    ...
    public virtual void Invoke(string message)
    {
        Time = DateTime.Now;
    }
}

internal class SubA : Base
{
    public override void Invoke(string message)
    {
        base.Invoke(message);
        // Do A
    }
}

internal class SubB : Base
{
    public override void Invoke(string message)
    {
        base.Invoke(message);
        // Do B
    }
}

然而,这确实使得派生类型根本不能调用基本方法。

如果没有调用基本功能并且您希望更加确定预期行为,那么它是灾难性的,您可能希望通过在基本方法的中间提供注入点来建立更强的契约:

internal abstract class Base
{
    ...
    public void Invoke(string message)
    {
        Time = DateTime.Now;
        this.InvokeCore(message);
    }

    protected abstract void InvokeCore(string message);
}

internal class SubA : Base
{
    public override void Invoke(string message)
    {
        // Do A
    }
}

internal class SubB : Base
{
    public override void InvokeCore(string message)
    {
        // Do B
    }
}