发表评论
非常好,每次你的文章都是那么的深入。。。。。佩服
想问下:为什么要使用接口
#5楼 [
楼主]2005-11-24 18:58 |
◎try
用interface是实现oo的关键
Allen Lee同学,我一直很喜欢你的风格:)
#10楼 [
楼主]2005-11-25 08:52 |
To try:
“为什么要使用接口”,如果我们在实时交流,我一定反问你“为什么要使用 OO”。我相信对于这些你都有你自己的答案的,只不过是好奇我的答案,所以才提出来。
好吧,假设你现在要为某公司招聘一批程序员,你肯定不希望某个人走到你面前告诉你他哪里不舒服然后叫你给他开点药,你公司也肯定不希望将来工作的时候才发现招进来的是一个小提琴手或者一个自称是程序员的骗子。OK,这些都必须在面试的过程中处理!从这个角度来看,面试的过程就是一个筛选的过程,而你就是执行筛选的人。还缺什么?当然是一个“筛子”,一个用于把你们想要的程序员识别出来的“筛子”。联想到什么了吗?接口的“选择性透过”!那么,接口为什么会有这种特性?接口是如何进行筛选的?你可以把接口看作一个标准、一个约定、一个规范或者别的类似的你能想到的。作为一名面试官,你不可能一接到公司的任务就直接冲上阵去,你会事先思考一下,公司究竟需要什么样的程序员,符合什么条件的程序员才会被招近来工作,否则你就不是一名合格的面试官了,因为你不但有可能会使公司的工作陷入困境,而且有可能会埋没一个人才,因为他可能在别的地方会有更好的发展,而你却让他进来无所事事。
接着,假设你们公司打算让这批程序员到美国分部从事 ASP.NET 的开发,那么你的“筛子”可以这样表达:
interface IProgrammerStaff
{
void SpeakEnglish();
void DevelopASPNET();
}
然后,你把“筛子”用到面试中去:
Interviewer you = new Interviewer();
you.Interviews(somebody);
现在,假设有一个脸色苍白的人走到你面前,但他递给你的不是简历而是病历,那么面试的具体工作当然就不会被展开,因为编译器不允许你这样做!
从这里你可以看出,接口的使用带有很强的目的性,你可以把它看作你对事物的一种期望,如果你压根就不知道想要什么,那你还是不要使用接口了。
最后我还有一点要说说的,interface 是狭义的接口,广义上,接口泛指任何形式的标准、规范、约束或者期望。
好了,我想该说的我都说了,如果哪位认为需要补充的或者有不同看法的,欢迎提出来一起研究。
接口,是写给接口的使用者看到
就好像是,图纸是画给施工人员看的
#13楼 [
楼主]2005-11-25 09:14 |
今天早上发现两件趣事:
1. 成了 linkcd 的同学;
2. 成了“.NET 新手 training 活动”团队的成员。
希望明天早上能发现更多的趣事,呵呵~~~
#14楼 [
楼主]2005-11-25 09:19 |
To 菩提树:
这当然!但为什么我们要写接口给使用者看呢?正如图纸向施工人员表明了设计师的想法一样,接口也向使用者表明我们的意图。从这个角度来看,接口是一种存在于设计者和使用者之间的约定,是一种把设计者的期望传递给使用者的沟通方式。
To Allen,
我觉得接口最重要的还是强制性吧,当一个类实现一个接口的时候,就必须提供接口所定义方法的具体实现。至于选择性,在类的继承关系中,不一样有体现吗?
在你评论中给出的例子,Interviewer类的Interviews方法的signature是这样的吧: public void Interviews(IProgrammerStaff candidate)。然后你说的选择性是不是somebody实例所属的类必须实现IProgrammerStaff的接口呢?
BTW:linkcd也是我的同学,哈哈~~
@Allen
一直关注你design方面的文章,受益非浅。古语有云:能者为师。以后想跟你多交流,多学习。没意见吧?MSN:JPWAR@163.COM
接口不仅可以掩盖共同实现者各自独有的方法,还可以掩盖共同实现者所不同的泛型类型参数。这一特点被我用在VBF中用作延迟执行(DelayInvoke)。
@FantasySoft
你终于出现了,怎么老不MSN上线呀……
#18楼 [
楼主]2005-11-25 09:43 |
To FantasySoft:
你说的也是对的,对于目标对象来说,接口具有强制性。还是拿面试这个例子来说,某人想进入我们公司么?能说流利的英语么?能熟练运用 ASP.NET 么?如果可以,那么此人是幸运的;否则,就只好回去学习学习了。而这个学习的过程明显就是实现 IProgrammerStaff 接口。从这个角度来看,设计师透过接口强制目标对象达到自己的期望。我们强制应聘者具备某些条件,如果应聘者不具备并且不愿学习,那么我们惟有请他走人了。
To Allen,
其实选择性不就是OO里面所强调的类型吗? 正如你正文里给出的例子,t是类ABC的实例,但是它的type却是ABC,这个在编译期就已经决定的了。类型确定了,也就是确定了这个实例的function table包含了哪些function,这里的包含实际上是指function的地址,而非function本身。至于function地址具体指向哪里则是在运行期决定的。 分清楚编译期和运行期所做的事情,对于理解OO中对象行为是很有帮助的。
To Ninputer,
原来我成通缉犯了,嘻嘻~~ 我有看到你上线啊,但是你都很忙,都不敢打扰你。我晚上都会上的,到时候见。 :)
接口就一个类的同性抽象,你需要的是ABC的功能,才调用设计这个ABC的接口,
使用时调用了一个Class1对ABC的实现,这个很正常
ABC t = new Class1();
但是,如果你要调用
((Class1)i).N();
只能说你的设计与调用不合理,或者你就直接
Class1 t = new Class1();
还要用接口吗?
接口是个很好的东西,定义要标准,就按标准来做,如果以前的标准不够强大,扩展一个
public interface ABC2:ABC
{
void N();
}
#22楼 [
楼主]2005-11-25 14:16 |
To FantasySoft:
你说的是对的。例如下面语句:
you.Interviews(somebody);
在编译期,编译器将会帮助你检查 somebody 是否实现了 IProgrammerStaff,只有类型匹配才能通过编译。这就相当于面试官设立一个初级检查站,看看应聘者能否提供某些书面资料来说明他具备英语交流能力和 ASP.NET 开发能力。而在运行期,Interviewer.Interviews 会进一步检查 somebody 的“工作效果”,把合适的人才招近来。从这个角度来看,接口的“选择性透过”特性就是类型检查。
To Allen:
嗯,嗯~~ 那么换了另外的角度,这个选择性透过还有其他的意思吗?
Allen Lee所说的招聘例子,我觉得是描述的泛型的抽象力而不是接口(面向对象)的抽象力。Interface不是通过那些成员“检查”哪些类型可以使用,而是一种让使用者不关心类型的具体实现就知道类型上面可以进行哪些操作,他知道这操作类型一定可以执行,但如何执行就是接口实现者的任务了。
那个招聘的例子,在.NET中恐怕只有VB9的Dynamic Interface可以胜任
#25楼 [
楼主]2005-11-25 21:08 |
To 装配脑袋:
Oh,你说的是对的,接口可以用来隔离实现,而这又是我们通常使用接口的原因之一。我得承认面试那个例子并不是一个好例子,它未能让大家以更多的角度去了解接口。
现在我用《多样式星期名字转换》的“反向方案”来举例。在该文中,我的目的是进行星期名字的转换,我期望转换器可以这样使用:
string name = nameConverter.ToString(day);
我把这种期望制定成一种标准,并以接口的形式表达出来:
interface INameConverter
{
string ToString(Day day);
}
客户端也通过 INameConverter 得知我的目的。由于我把这种期望上升为一种标准,于是它具备了一种强制性,犹如法律一般。而 NameConverter 的
public void AddInnerNameConverter(INameConverter innerNameConverter);
使得我可以通过编译器的编译期类型检查把这种强制性加在客户端所传递的对象上。仅当这一切都 OK 才会有下文。
“反向方案”的一个很重要的特征就是透过 INameConverter 隔离具体的转换实现,这点可以在 NameConverter 的
public string ToString(Day day)
{
foreach(INameConverter nameConverter in m_NameConverters)
{
m_Content.AppendFormat("{0} ", nameConverter.ToString(day));
}
return m_Content.ToString().TrimEnd();
}
中得到体现。NameConverter 是一个“总管事”的角色,它不是负责具体的转换工作,而是负责把整个转换工作分配给具体的“员工”。NameConverter 没必要也不可能知道具体的转换细节,而 INameConverter 就发挥了隔离这些细节的功效了。
从这里我们可以看出,从顶层的 Conceptual Perspective 到中层的 Specification Perspective 再到底层的 Implementation Perspecitive,视角的转变让你看到接口的不同侧面。我觉得我们现在已不仅仅在简单的回答“为什么要使用接口”了,而是在试图回答“什么是接口”,这个问题对于我们就犹如“什么是人性”对于心理学家一样,不同的人从不同的角度会得出不同的看法,甚至一个理论体系。人性是复杂的,现代心理学已倾向于把各派的观点看作是人性的某一剖面。同样的道理,接口也会因为情况的不同和视角的不同而让我们得到不同的见解。
最后,在我看来,接口还有一个剖面我没有提到的——角色扮演。我们知道一个类可以实现多个接口:
class Consultant : IEmployee, IStockholder
{
// ...
}
上面这个 Consultant 代表某咨询公司的咨询师既是该公司的员工,也是该公司的股东。
我认为真正的问题并不在于 t 究竟是什么,而是在于我们为什么要这样使用接口
_________________________
个人感觉这样写的意思就是代表某个对象实现了接口这个契约了吧,
记得过去看过好像是说接口是面向开发者的,而类则是面向对象的,呵呵
浅显的见解,希望大家不要耻笑…………
这个问题至于这样研究么???
ABC t = new Class1();
t.N();
编译就会出错,所以通过 ABC t = new Class1() 这句话我们得到的肯定不是 Class1 的一个实例。但是接口是不可以实例化的,那么 ABC t = new Class1() 究竟实例化了一个什么东西?
这里得描述有错误!这里实例化得当然是class1得实例,因为调用得是class1得构造函数。但是为什么不能用t.N()呢,这是因为编译器仅仅知道t是符合ABC接口的一个实例,但是它并不知道t到底是属于继承该接口的哪个类,也就是说它不知道t的身份,只知道它能干M这件事,至于它在接口以外还有什么别的本事一概不知。它不知道t是class1还是class2或者别的,所以你用t调用N肯定不行,除非你用Class1 t=new Class1();那么编译器就会明白的知道这个t是class1。
# re: 我是谁?[C#] 2005-11-30 16:19 xiao_p
我认为真正的问题并不在于 t 究竟是什么,而是在于我们为什么要这样使用接口
_________________________
个人感觉这样写的意思就是代表某个对象实现了接口这个契约了吧,
记得过去看过好像是说接口是面向开发者的,而类则是面向对象的,呵呵
浅显的见解,希望大家不要耻笑…………
~~~~~~~~~~~~~~~~~~~~~~~~~~~
这个说得是没错的。首先,可以看出类可以从接口继承,也就是说,接口里面的函数,属性是它子类的一个子集。每个从接口继承类可以包含更多的接口没有的个性。
接口是所有子类的一种共性。通常它规定了某一种对象必须具有的功能。你可能不知道它到底是汽车,还是火车,但是你却知道它是一种车,车能跑,能停,就行了。
5066还句话说,t在声明的时候是符合ABC规范的指针或者句柄,而不是符合class1。
好文章,可以给同学们留下深刻的印象!
根据我的理解,这不仅仅是接口的特点吧,基类应该可以得到同样的效果。
有位仁兄问得好:接口到底有什么用。
斗胆借此谈一谈自己的看法:接口比基类更加形式化、更空泛。表现在下面两个方面——
很多API提供接口来实现不同环境间的数据、功能传递;接口使我们可以安全地实现多重继承。
个人看法,不要因为可以去掉就去掉接口的定义,也许会有我们一下看不到的好处。
接口的实现者与接口之间是can-do的关系,也就是说,Class1 can-do ABC的方法,但这并不代表ABC can-do Class1的方法
同样,子类与基类之间是is-a的关系,因此,SubClass is-a BaseClass,而BaseClass is-not-a SubClass
看了你的文章让我受益匪浅!:)
@hoodlum
你可能不知道它到底是汽车,还是火车,但是你却知道它是一种车,车能跑,能停,就行了。
——————————————————
如果强调能跑,能停,那么应该建立一个能跑能停的接口(不一定实现这个接口的一定是车,还可以包括动物、机器人等等。。。)
如果强调是一种车,还是建议用抽象类
to Allen Lee.
您好,未先经您同意,我已转载了您BLOG上的部份文章(当然有出处和原文引用).
如果您觉得不合适,我会删除!同时希望您能写更多的好文章!
谢!.
Benyu.
在c++的概念里
不光是接口
子类的非重新方法,对象
在基础类的对象中都不能访问
从思想上说
子类是基础类功能的扩展
在不修改基础类私有功能和数据的前提下
兄台 我觉得你说的是对的 楼主的讲解很有意思 也有道理 但是并没有把接口给我们完全讲透彻 只能说讲解了接口的部分内涵@hoodlum
// Code #04
((Class1)i).N();
根据上下文,这里的 i 应该是 t 吧...
#39楼 [
楼主]2006-12-15 19:43 |
To 小新:
谢谢,原文以更正 ^_^