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

6
我有以下代码
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
    }
}

我有SubA和SubB两个类,它们都继承自Base类。你可以看到有一段代码在重复设置时间,是否有办法将设置时间的功能移到Base类中?

6个回答

6
你可以像这样做:

你可以像这样做:

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
    }
}

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
    }
}

在这种情况下,SetTime 应该受到保护。 - PVitt

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
{
}

在子类中,您仍然可以覆盖该方法,以便在需要不同实现的情况下使用。


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
    }
}

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

invoke方法仅在Base类的此实例中被覆盖。这提供了更大的灵活性,并有助于避免不必要的子类化。

有关详细信息,请查看Patrick Steele的精彩文章


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
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接