【问题标题】:Abstract class, how to avoid code duplication?抽象类,如何避免代码重复?
【发布时间】:2012-02-16 10:28:38
【问题描述】:
我有以下代码
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 类,你可以看到我有一个重复它的代码,它正在设置时间,有没有办法将时间设置移动到基类?
【问题讨论】:
标签:
c#
inheritance
abstract-class
【解决方案1】:
你可以这样做:
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
}
}
【解决方案2】:
有很多可能的解决方案。
这取决于您希望何时设置此属性。
如果您想立即使用,可以在 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
}
}
【解决方案3】:
改用虚方法:
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
{
}
您仍然可以在需要不同实现的子类中覆盖该方法。
【解决方案4】:
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
}
}
【解决方案5】:
有两种实用的选项,具体取决于您希望代码合同的严格程度。
您可以将逻辑移动到虚拟方法中,并允许子类型选择重载行为。
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
}
}
【解决方案6】:
已经有很多答案了。作为一种替代方法(有点像忍者),我将建议 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 类的这个实例覆盖。这提供了更大的灵活性并有助于避免不必要的子类化。
查看awesome post from Patrick Steele 了解详情。