C#在基类/抽象类中的最佳部分接口实现
本文关键字:最佳部 接口 实现 基类 抽象类 | 更新日期: 2023-09-27 18:23:42
.net不允许在基类中实现部分接口。作为缓解措施,我提出了3种替代解决方案。请帮助我决定在重构、编译/运行时错误和可读性方面哪个更通用。但首先是几条评论。
- 当然,您可能总是将对象强制转换为IFoo,并在没有任何编译器警告的情况下调用任何方法。但这不符合逻辑,你通常不会这么做。这个构造不会因为重构而出现
- 我想要最大的间距。直接类约定(公共方法和属性)应该与接口实现分开。我经常使用接口来分隔对象交互
我的比较:
- BaseClass1/MyClass1:
- con:必须在BaseClass1中为IFoo的每个未实现的方法创建虚拟抽象
- con:额外的方法包装-在运行时对生产力有轻微影响
- BaseClass2/MyClass2:
- con:如果MyClass2中没有Method2的实现,则没有编译器警告。运行时异常。单元测试覆盖率低的重构可能会破坏代码的稳定
- con:必须放置额外的过时构造,以防止从子类直接调用方法
- con:Method2对于BaseClass1是公共的,所以它现在是类约定的一部分。必须放置"Obsolete"构造以防止直接调用,而不是通过IFoo
- BaseClass3/MyClass3:
- pro:(与#2相比)。可读性更强。您可以看到MyClass2.Method2是IFoo实现,而不仅仅是某个overriden方法
public interface IFoo
{
void Method1();
void Method2();
}
public abstract class BaseClass1 : IFoo
{
void IFoo.Method1()
{
//some implementation
}
void IFoo.Method2()
{
IFooMethod2();
}
protected abstract void IFooMethod2();
}
public class MyClass1 : BaseClass1
{
[Obsolete("Prohibited direct call from child classes. only inteface implementation")]
protected override void IFooMethod2()
{
//some implementation
}
}
public abstract class BaseClass2 : IFoo
{
void IFoo.Method1()
{
//some implementation
}
[Obsolete("Prohibited direct call from child classes. only inteface implementation")]
public virtual void Method2()
{
throw new NotSupportedException();
}
}
public abstract class MyClass2 : BaseClass2
{
public override void Method2()
{
//some implementation
}
}
public abstract class BaseClass3 : IFoo
{
void IFoo.Method1()
{
//some implementation
}
void IFoo.Method2()
{
throw new NotSupportedException();
}
}
public abstract class MyClass3 : BaseClass3, IFoo
{
void IFoo.Method2()
{
//some implementation
}
}
我喜欢这个版本,基类不能实例化,因为它是抽象的,派生类必须在声明中列出IFoo,否则它就不会实现接口,然后它只负责实现接口的其余部分。我看到的一个缺点是,你不能在基类中显式地实现接口方法(即没有IFoo:Method1),但除此之外,这是一个开销相当低的版本。
public interface IFoo
{
void Method1();
void Method2();
}
public abstract class BaseClass1
{
public void Method1()
{
//some implementation
}
}
public class MyClass1 : BaseClass1, IFoo
{
public void Method2()
{
//some implementation
}
}
好的,您可以尝试以下操作,因为BaseClass
是抽象的:
public interface IFoo
{
void Method1();
void Method2();
}
public abstract class BaseClass : IFoo
{
public void Method1()
{
// Common stuff for all BaseClassX classes
}
// Abstract method: it ensures IFoo is fully implemented
// by all classes that inherit from BaseClass, but doesn't provide
// any implementation right here.
public abstract void Method2();
}
public class MyClass1 : BaseClass
{
public override void Method2()
{
// Specific stuff for MyClass1
Console.WriteLine("Class1");
}
}
public class MyClass2 : BaseClass
{
public override void Method2()
{
// Specific stuff for MyClass2
Console.WriteLine("Class2");
}
}
private static void Main(string[] args)
{
IFoo test1 = new MyClass1();
IFoo test2 = new MyClass2();
test1.Method2();
test2.Method2();
Console.ReadKey();
}
设计一个没有实现定义良好的契约的类是非常糟糕的。这是极端的,因为你首先说一个班有能力做某事。您明确强调了类可以做的事情,但在代码的后面,您说nahh,见鬼去吧,这个类可以在没有实现的情况下生存。编译器非常明智地要求您执行合同,但这由您自己决定。
以下是的一些常见解决方案
错误的解决方案
- 引发异常(NonImplementedException或NotSupportedException,请参阅示例)
- 宣布它过时(从一开始就设计好)
更好的解决方案
- 显式接口实现,但您仍然实现它(只是有点隐藏它)
最佳解决方案
- 使用界面分离(将脂肪界面分割成更薄、更易于管理的界面)
我建议让抽象基类用调用protected abstract
方法的方法实现接口,如您的第一个示例所示,除了一些派生类可能无法实现的方法(遵循"将所有东西都放入IList
,但并不是所有方法都能实际工作"模式);这些可以是抛出CCD_ 5的CCD_。
请注意,是否将接口的任何特定成员公开为类似名称的公共成员(可以调用适当的抽象成员)取决于子类。
VB.net中合适的模式应该是类似MustOverride Sub IFoo_Method1() Implements IFoo.Method1
的模式,这样可以避免额外的函数调用开销,但C#没有提供任何实现具有受保护成员的接口的方法。对任何可能必须在子类中重写的方法使用显式接口实现都有点恶心,因为子类对接口的重新实现不可能链接到父类的实现。