为什么要用接口(从编程角度)

moondreamyou 2011-11-09 11:01:48
接口很好大家都知道,但好在哪里却不一定说得出来,至少说得不通俗,或只是人云亦云。我现在所知道的接口好处有以下几点(从编程角度),但我想知道更多更深的好处以及适用场景,而不是为了接口而接口。
假设有一个接口
interface IX
{
int GetMax(int a,bool b);
}

好处:
1.我可以通过往一个IList<IX>立面添加继承了IX接口的对象,然后用foreach(ix in LIST){ix.GetMax(1,true)};因为方法名相同,但如果没用接口我就不能这样调(例如某个类也有GetMax方法,但参数为3个)。
2.继承了IX接口的类,我就知道它具备GetMax方法,但如果没用接口,我必须去看看那个类的GetMax是否真的符合我的调用需求,甚至那个类可能根本就没有GetMax方法,但却有GetMaxValue方法,作用一样只是名字不一样。如果多人开发,用接口减少了很多沟通和解释。
3.修改接口继承类中的实现方法,调用者不需要修改代码。比如很多地方都用了ix.GetMax(1,true),修改具体接口实现类的方法,我调用的地方不用做修改。(但这里这样解释不准确,因为我如果不用接口,直接在类中改实现方法,只要参数返回值相同,也不用修改调用的地方,请高手说明)
4.可以通过工厂和反射来创建具体的继承IX的实现类,调用者甚至都不知道具体最终调的是哪个实现类的方法。修改实现类的时候,对于调用者做到真正透明。
5.一开始就针对应用定义出需要的接口方法,然后逐步细化,而不会遗漏,而不是一开始就建类,然后不断的补方法,最后弄得这个类很臃肿。
6.多人开发时,我负责A模块开发,要调用GetMax方法,一开始就可以写,尽管负责写GetMax方法的人还没真的写出具体的方法来。但如果不用接口,我要调他的方法,我还要先问他那个获取最大值的方法是不是叫GetMax,是不是返回int,等。
7.在多继承时,接口提供了灵活的机制,我没必要为了统一一个GetMax的方法,就去搞一个抽象类A,万一将来又想统一一个GetName方法,又在抽象类A中加GetName方法?这显然不合理,因为GetName可能更GetMax可能都不是一个范畴的东西,硬要拉在一起,破坏了类的单一职责。
8.接口看起来更简洁。

希望各位告诉我接口还有什么好处?请用具体的场景或代码说明,以上列举如有错也请指出。
...全文
1223 42 打赏 收藏 转发到动态 举报
写回复
用AI写文章
42 条回复
切换为时间正序
请发表友善的回复…
发表回复
李支锋 2013-11-27
  • 打赏
  • 举报
回复
嗯,赞同,赞同
hetengfei_ 2011-11-17
  • 打赏
  • 举报
回复

唉,始终不见大牛的出现啊。

不能说得就连不会编程的都连连称好
threenewbee 2011-11-11
  • 打赏
  • 举报
回复
有很多问题,其实是为了答案而诞生的问题,很多人认为,学习知识就是搞清楚这些问题的答案。事实上这些问题一点用也没有。

比如,人为什么要活着?人因为活着而活着,难道不为了什么就不活了么?
你为什么要学编程,学编程的好处是什么?有的人学医学,有的人当老师,有的人当艺术家,你选择了写程序,事实上这种选择的本质是,可能你可能没有艺术细胞,生物学得不好,学编程正合适,事实上不是编程有什么优势,而是你学编程是你最好的选择,换成齐白石,你说的这些好处有什么意义呢?
再比如,你为什么要用C#而不是Java,难道因为Java不支持委托,就不好么?或者Java支持跨平台就如何如何了么?

中国人从小就喜欢学习什么中心思想、段落大意,研究的思想连作者都想不出来。难道说你的写作水平超越作家了么?编程也是一样。你有没有想过,“接口有什么好处”这个问题本身一点意义都没有,也许你想的是,不能吧,没有意义的问题为什么我的老师要问呢?我的同学在讨论呢?我考试要考呢?我难道不把接口的好处说出个子丑寅卯就能学会编程?如果你这么想的,这很正常。

但是有朝一日,当你真的觉得编程有些心得了,再来看看我说的这些,你就能体会我说的意思了。
threenewbee 2011-11-11
  • 打赏
  • 举报
回复
我随便举一个.NET Framework框架里面用到接口的例子:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<Person> dataSource = new List<Person>()
{
new Person() { Age = 32, Name = "张" },
new Person() { Age = 20, Name = "刘" },
new Person() { Age = 43, Name = "马" },
new Person() { Age = 12, Name = "刘" },
new Person() { Age = 17, Name = "陈" }
};
for (int i = 0; i < dataSource.Count; i++)
Console.Write("\t" + dataSource[i]);
Console.WriteLine();

// 使用接口,需要再定义一个类
List<Person> list1 = dataSource.ToList();
list1.Sort(new PersonComparer());
for (int i = 0; i < list1.Count; i++)
Console.Write("\t" + list1[i]);
Console.WriteLine();

// 使用预制的泛型类
List<Person> list2 = dataSource.ToList();
list2.Sort(new Comparison<Person>((x, y) => x.Age - y.Age));
for (int i = 0; i < list2.Count; i++)
Console.Write("\t" + list2[i]);
Console.WriteLine();

// 使用LINQ,最简单
List<Person> list3 = dataSource.ToList();
list3 = list3.OrderBy(x => x.Age).ToList();
for (int i = 0; i < list3.Count; i++)
Console.Write("\t" + list3[i]);
Console.WriteLine();
}
}

class Person
{
public string Name { get; set; }
public int Age { get; set; }
public override string ToString()
{
return Name + "[" + Age + "]";
}
}

class PersonComparer : IComparer<Person>
{
public int Compare(Person x, Person y)
{
return x.Age.CompareTo(y.Age);
}
}

}


对于同一个集合排序,有很多方法,在这里,接口是实现最复杂的,它的好处在哪里?
yangniao 2011-11-11
  • 打赏
  • 举报
回复
希望继续。。。。
threenewbee 2011-11-11
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 moondreamyou 的回复:]
引用 5 楼 vrhero 的回复:
接口是软件工程学概念...如果你不能理解,那么那些编程语言级的枝末细节就没有什么意义...本末倒置是不可能具备“实用性”的...

可能我提及的一些好处比较狭窄,并不一定符合所有的语言,但接口一定有其共性的编程便利等好处。如果你不能用事实说话,那么你也是不懂的,我就知道很多人为了接口而接口,为了架构而架构,但任何事情都有适用场合,接口有用不一定就是任何时……
[/Quote]

看了下,vrhero的观点基本和我一致,只是他没有耐心和你摆扯这些基本的例子、Sandy945的观点可以作为我的补充。(注意区分软件设计的“接口”概念和C#语言提供的“interface”关键字,两者并不相干)
threenewbee 2011-11-11
  • 打赏
  • 举报
回复
之前我提到,松本行弘(ruby创始人)的新书中提到,所谓面向对象的核心价值,也并非对现实事物的模拟,它也仅仅是更好地为实践软件设计的一些方法论提供的工具(比如说抽象、重用,对数据的结构化等等)。

同样的道理,接口也并非一定是“插头”的作用,或者和软件设计搭上界。
threenewbee 2011-11-11
  • 打赏
  • 举报
回复
[Quote=引用 36 楼 sandy945 的回复:]
接口的使用并非总是从设计的角度来考虑。接口和C#其他语法现象一样,共同构成了C#整个语言体系。
------------------------------------------------
我当时回复的时候,并没有想C#中的接口。

我认为在设计领域中才能更好的体现接口的意义,并不只是计算机范畴。

在程序设计这个(设计领域)子集中,接口的意义要和语言相结合。

接口的意义在于……
[/Quote]

正确。所以说,语言层面不承担优化设计的责任。设计是架构师的事情,而不是语言元素解决的。

C#的接口(所谓interface关键字),其实一个很大的作用不是说“通用或者替代性”,如我举的例子,IComparer的例子,它仅仅是把部分算法实现推迟给调用者自己来做,在这一点上,委托也能做同样的事情,而且做的更好,而Lambda表达式则做的更好。虽然本质上它们等价,但是少写一个类或者一个方法在实际使用的时候是大大的简洁。虽然我们知道在IComparer的例子里面我们可以单独地测试那个PersonComparer,我们可以替换PersonComparer的实现,我们可以把PersonComparer用在别处,但是请相信我,更多的时候,只是为了给Sort方法准备一个参数,并且只用一次。
阿非 2011-11-11
  • 打赏
  • 举报
回复
接口的使用并非总是从设计的角度来考虑。接口和C#其他语法现象一样,共同构成了C#整个语言体系。
------------------------------------------------
我当时回复的时候,并没有想C#中的接口。

我认为在设计领域中才能更好的体现接口的意义,并不只是计算机范畴。

在程序设计这个(设计领域)子集中,接口的意义要和语言相结合。

接口的意义在于 抽象、不拘细节

从而使同类事物在同一高度具有通用及可替代性。


关于解耦,并不是接口能解耦,而是抽象能解耦 接口只是手段

还有一点,如果两个事物有必然联系,那么就不会出现完全解耦,只能耦合转移。
threenewbee 2011-11-11
  • 打赏
  • 举报
回复
很明显,委托,或者说发布者/订阅者可以使用更松的耦合。相比较而言,不恰当地使用接口,它的优点恐怕就不存在了。

在委托里面,并不需要订阅者去实现一个预制的接口,事实上接口解开了调用者和被调用的耦合,而把这种耦合转嫁给了调用者和接口,因此接口本身就不能修改了。而订阅者模式里面,不存在这样的依赖关系,只要方法签名适配,就可以调用。

另一方面,接口相对于函数调用,是解耦,但是函数调用是耦合紧密的么?不是。和一个整个代码相比,函数调用实现了调用者和被调用者内部实现的解耦,把这种耦合转嫁给了调用关系上。因此函数调用也有“解耦”的好处。

那么“解耦”本身是好处么?我先不回答这个问题,我只举一个例子,我们知道旅客列车一般挂17个车厢,那么这么做有什么好处呢?比较灵活,你想,如果火车只有1个车厢,转弯都很困难。但是是不是拆分成170个车厢更好呢?显然也不是。170个车厢反而使得编组列车更加困难。

代码也一样。过度的“解耦”导致的后果是,系统中的模块过多,而你不得不想办法把它们装配起来。装配的过程就是耦合的过程。

极端的例子,一行代码一个模块,最最解耦的程序其实是最最耦合乃至混乱的程序。
threenewbee 2011-11-11
  • 打赏
  • 举报
回复
[Quote=引用 32 楼 sandy945 的回复:]
引用 29 楼 caozhy 的回复:
对于同一个集合排序,有很多方法,在这里,接口是实现最复杂的,它的好处在哪里?

从我的角度,我认为这个例子根本说明不了问题。

用语法糖的调用和低层次的实现比较毫无意义,二者本就不对等。

从设计的角度,接口只有谁比谁更优雅,但细节的实现则是谁比谁更猥琐。
[/Quote]

恰恰就是我想说的。接口的使用并非总是从设计的角度来考虑。接口和C#其他语法现象一样,共同构成了C#整个语言体系。

当然这个例子还可以说明另外一些问题。那就是,接口的确是可以用来“解耦”,但是和观察者模式,和委托相比,接口的耦合还不够松散。

如果用接口来设计WindowsForms里面的按钮,是这样的:
class MyForm : IButtonClick, IButtonDblClick, IButtonKeyDown...
{
MyForm()
{
button1.Click.Add(this);
button1.DblClick.Add(this);
...
}
void IButtonClick.Click(object sender, object args)
{
if (sender == button1) ...
}
void IButtonDblClick.DblButton(...)
{
...
}
}

class Button
{
public List<IButtonClick> ClickTargets { get; set; }
...

public override void WndProc(Msg msg)
{
...
if (msg == WM_CLICK)
{
foreach (IButtonClick target in ClickTargets)
target.Click(this, arg);
}
}
}
hetengfei_ 2011-11-11
  • 打赏
  • 举报
回复
高手们不要争论,
要举例子。
谁举的例子最有说服力,就信谁的。
阿非 2011-11-11
  • 打赏
  • 举报
回复
[Quote=引用 29 楼 caozhy 的回复:]
对于同一个集合排序,有很多方法,在这里,接口是实现最复杂的,它的好处在哪里?
[/Quote]
从我的角度,我认为这个例子根本说明不了问题。

用语法糖的调用和低层次的实现比较毫无意义,二者本就不对等。

从设计的角度,接口只有谁比谁更优雅,但细节的实现则是谁比谁更猥琐。
hetengfei_ 2011-11-11
  • 打赏
  • 举报
回复
[Quote=引用 30 楼 caozhy 的回复:]
有很多问题,其实是为了答案而诞生的问题,很多人认为,学习知识就是搞清楚这些问题的答案。事实上这些问题一点用也没有。
[/Quote]

我想追问下,

接口:
接口是不是一些用得很广的类。
大家在决解问题时可能要用这些类。 但是懒得去写,就去继承他算了。
但又不想现在就继承--因为现在继承代码变得复杂,而且不知用不用得到。
所以故意留个坑在那,等到用到再去继承他?
那个坑 就叫接口?

是这样理解吗?
moondreamyou 2011-11-10
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 zhujiazhi 的回复:]
并行开发
测试方便
解耦合
[/Quote]
并行开发可以理解,我的例子中也有提到。但测试方便和解耦合,如何体现?
moondreamyou 2011-11-10
  • 打赏
  • 举报
回复
另外我这里说的接口只是编程上的接口,而非概念上的接口。对于那些银行支付接口,WebService等,某种角度来看也可以算接口,但不是我这里讨论的。
moondreamyou 2011-11-10
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 vrhero 的回复:]
接口是软件工程学概念...如果你不能理解,那么那些编程语言级的枝末细节就没有什么意义...本末倒置是不可能具备“实用性”的...
[/Quote]
可能我提及的一些好处比较狭窄,并不一定符合所有的语言,但接口一定有其共性的编程便利等好处。如果你不能用事实说话,那么你也是不懂的,我就知道很多人为了接口而接口,为了架构而架构,但任何事情都有适用场合,接口有用不一定就是任何时候都应该用接口。我问这个问题的原因就是想从实际的编程场景来重新理解我对接口的定义。
myhaikuotiankong 2011-11-10
  • 打赏
  • 举报
回复
[Quote=引用 27 楼 caozhy 的回复:]
“解耦”、“测试”、“契约”这些好处不是接口带来的,而是一个称职的程序员合理的设计带来的。换一句话说,如果你不懂哪些东西要和哪些东西解耦,如何测试,订立什么样的契约,你用了接口你也达成不了这样的目的。一个称职的程序员用任何语言,用任何方法,都可以达成这样的目的。

比如,钢铁没有位移速度快的好处,只有人造出汽车才有。沙子也没有计算速度快的好处,同样需要人把它变成芯片。

有的人说,我的代码……
[/Quote]有道理
threenewbee 2011-11-10
  • 打赏
  • 举报
回复
“解耦”、“测试”、“契约”这些好处不是接口带来的,而是一个称职的程序员合理的设计带来的。换一句话说,如果你不懂哪些东西要和哪些东西解耦,如何测试,订立什么样的契约,你用了接口你也达成不了这样的目的。一个称职的程序员用任何语言,用任何方法,都可以达成这样的目的。

比如,钢铁没有位移速度快的好处,只有人造出汽车才有。沙子也没有计算速度快的好处,同样需要人把它变成芯片。

有的人说,我的代码可以方便地把这个替换成那个。但是如果它们是一堆垃圾,替换来替换去,还是垃圾的组合。
threenewbee 2011-11-10
  • 打赏
  • 举报
回复
我说了,接口不存在好不好的问题,也和什么“解耦”、“测试”、“契约”一点关系也没有。

事实上,现代软件设计方法,都是围绕解耦、重用这个中心展开的。也许你看到接口解决了“解耦”很新鲜,但是明天你又看到了原来委托也有这么一个好处,原来泛型也有这么一个好处,原来继承也有这么一个好处,原来函数重载也有这么一个好处,原来扩展方法也有这么一个好处……原来C#语言处处都有这么一个好处,原来现代编程语言都有这么一个好处,试问,这算“好处”吗?
加载更多回复(22)

62,073

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术交流专区
javascript云原生 企业社区
社区管理员
  • ASP.NET
  • .Net开发者社区
  • R小R
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

.NET 社区是一个围绕开源 .NET 的开放、热情、创新、包容的技术社区。社区致力于为广大 .NET 爱好者提供一个良好的知识共享、协同互助的 .NET 技术交流环境。我们尊重不同意见,支持健康理性的辩论和互动,反对歧视和攻击。

希望和大家一起共同营造一个活跃、友好的社区氛围。

试试用AI创作助手写篇文章吧