前言
嗨,大家好!
想象一下,你正在编写一段代码,突然发现现有的接口缺少某些功能,但问题是,这个接口已经被好多类实现了,你又不想破坏已经实现该接口的所有类。
这时候,你会怎么破呢?
传统一般有两种解决方法:
-
直接在现有的接口中添加新的功能,并手动为接口的所有实现类增加新的实现方法,如果接口的实现类很多,这种方式不仅耗时,也容易出错,违反了 “开放封闭” 的开发原则
-
另一种方法,添加新的接口,实现类实现新接口的功能,这样虽然符合 “开放封闭” 的开发原则,但会增加很多接口,和由此增加维护管理工作,如果实现类很多,且都需要新的功能,这种方式也是非常耗时的。
通常来说,我们有两个选择:
-
直接硬上:在现有的接口里加新方法,然后一个接一个地去每个实现类里补上新的实现代码。这种方式虽然直接,但如果实现类太多,不仅耗时,也容易出错,违反了 “开放封闭” 的开发原则。
-
另起炉灶:创建一个新的接口,让需要新功能的类去实现它。这样做确实符合"开放封闭"原则,但会增加很多小接口,和由此增加的维护管理工作,要是实现类很多,也挺耗时的。
这两种办法多少都有些副作用,如果能直接在接口里添加新的方法并提供默认实现,是不是会方便很多呢?
好消息是,C# 已经为你考虑到了这一点!从 C# 8.0 开始,我们可以直接在接口中定义带有实现的方法——这就是所谓的默认接口方法。
今天,我们就来聊聊这个新特性,看看如何在你的项目中使用它。
什么是默认接口方法
默认接口方法就是指可以在接口中定义的方法,这些方法不仅可以声明签名,还可以包含具体的实现逻辑。
这些方法即使你不在实现类中重写,实现类也可以直接调用它们。
public interface IAnimal
{
void Speak() => Console.WriteLine("一些动物的叫声"); // 默认实现
}
原理
当你在一个接口中定义了一个带有实现的方法时,编译器实际上会在每个实现该接口的类中创建一个隐式的继承链。
如果类没有提供自己的实现,则会自动使用接口中的默认实现。
这种设计使得我们可以在不改变现有代码的情况下,向接口添加新功能,而不会破坏依赖于旧版本接口的类。
下面我们通过一个 Step By Step 例子来感受一下它的魅力!
Step By Step 例子
1. 创建一个 .NET Core Console 项目
首先,在 VS IDE 中创建一个新的控制台应用程序项目,命名为 DefaultInterfaceMethodSample
2. 定义接口
定义一个名为 IAnimal 的接口,并在其中添加一个默认方法 Speak(),代码如下:
namespace DefaultInterfaceMethodSample
{
public interface IAnimal
{
void Eat();
// 默认方法
void Speak()
{
Console.WriteLine("这个动物发出声音");
}
}
}
3. 实现接口
定义两个实现这个接口的类,分别名为 Dog 和 Cat
public class Dog : IAnimal
{
public void Eat()
{
Console.WriteLine("狗吃牛肉");
}
// 使用默认实现
// public void Speak() { } // 可以选择是否重写
}
public class Cat : IAnimal
{
public void Eat()
{
Console.WriteLine("猫吃鱼");
}
public void Speak()
{
Console.WriteLine("喵喵~");
}
}
4. 调用接口方法
在 Program.cs 文件中创建这些实现类的实例并调用它们的方法
using DefaultInterfaceMethodSample;
IAnimal dog = new Dog();
dog.Eat(); // 输出: 狗吃牛肉
dog.Speak(); // 输出: 这个动物发出声音。
IAnimal cat = new Cat();
cat.Eat(); // 输出: 猫吃鱼
cat.Speak(); // 输出: 喵喵~
5. 运行程序
按 Ctrl+F5 编译并运行程序,你会在控制台看到如下图输出:
优势
从上面的例子中,我们可以看到一些默认接口方法的优势:
向后兼容性:可以在不改变接口的情况下,向其中添加新的方法,避免了影响已有实现的风险
减少冗余代码:以在接口中集中管理一些通用的逻辑,实现代码复用
更灵活的设计:允许新的实现类可以根据需要选择使用默认实现或自定义特定行为
缺点
当然,默认接口方法打破了传统接口的局限,也不可避免地会带来一些缺点,不可不察:
过度使用默认接口方法可能导致接口定义的复杂性增加,降低了接口的清晰性,增加维护的难度
将太多逻辑放入接口可能导致接口像一个 “上帝对象”,违反了单一职责原则
总结
总的来说,默认接口方法就像是给接口装上了 “超能力” —— 它们不仅保留了接口原有的灵活性,还能直接在接口里塞进具体的方法实现。
这样一来,即使我们后来往接口里加新功能,也不会让现有的代码改动很大,保持了很好的向后兼容性。
不过嘛,这也带来了一点小麻烦:传统的接口概念有点被打破了,不再是纯粹的 “契约”。因此,在设计时我们要特别留个心眼,别让接口变得太复杂,失去原本的清晰度。
所以,我们既要享受它带来的便利,但也要注意适度使用,别让接口变得太复杂!
好了,今天的分享就到这里啦,如果觉得有用,别忘了点个【赞与在看】哦,你的支持是我最大的动力!
最后,如果你有更好的想法或建议,欢迎留言讨论!
往期精彩
我是老杨,一个执着于编程乐趣、至今奋斗在一线的 10年+ 资深研发老鸟,是软件项目管理师,也是快乐的程序猿,持续免费分享全栈实用编程技巧、项目管理经验和职场成长心得!欢迎点击下方卡片关注老杨的公众号(名称:代码掌控者),更多干货等你来!
评论前必须登录!
注册