首页  编辑  

接口的讨论

Tags: /超级猛料/Language.Object Pascal/面向对象和类、VCL核心/   Date Created:

来自:cheka, 时间:2001-9-13 22:39:00, ID:624833

以前我在 CSDN 里 Java 版参与的接口讨论:

在<<thinking in Java>>中,Interface 是和Inner Classes 放在一起说的,

两者关系很紧密(并非是说Inerface只能指向Inner Classes的类).

建议好好看看该书的第8章的例子,如果你也曾读过<<VC++技术内幕>>(第四版)

中模拟COM的C++代码,会发现两者Interface(C++中表现为一个纯虚类)的使用

方法如出一辙.

我个人感觉接口在应用概念上与基类是有差别的,比方说有一个组合音响类,

那么"家电"是它的基类,而"CD机","功放"则是它的接口,如果一个用户只想使用

"CD机",那么他可以仅仅与"CD机"这一接口打交道(当然一定会存在整个音响的

对象实例,但对用户是透明的),这也是COM的基本原理.

来自:yysun, 时间:2001-9-14 3:58:00, ID:624988

我来细说不同的 interface

1. Java 中的 Interface

Java 取消了多重继承, 却引入Interface作为基本语言要素来实现类似多重继承的功能.

Java中的Interface是一种没有实现(implementation)的纯虚拟类. 同样拿"组合音响"做例子.

我们可以定义一个组合音响 interface, 然后, 做出索尼音响, 爱华音响, 先锋音响类 ...

组合音响 interface 是虚的, 只有定义: 电源200/50, 输出200w, 5盘CD机 ...

由具体的类如索尼音响来这些功能实现, 实现方法可以各异.

interface 组合音响 {

   public void play();

}

class 索尼音响 extends 家电 implements 组合音响 {

   public void play() {

       // 用索尼6通道环绕系统

       ......

   }

}

2. C++ 中的 Interface

我的印象中 C++ 是没有 Interface 作为基本语言要素的.它有多重继承和 template.

class 组合音响 {

   virtual public void play()=0;

}

class 索尼音响 : public 家电, public 组合音响 {

   public void play();

}

void 索尼音响::play() {

  ......

}

这里的组合音响必定是个类. C++中没有看到过 :

interface 组合音响 {

}

3. COM 中的 Interface

COM 中的 Interface 概念是独立于 C++ 本身语言概念以外的东西, 是为了方便不同语言

之间相互调用而设立的规范(用IDL来描述的, 存放于所谓typelib中). 看 VC++ 实现

Interface 用了很多 template 和宏来完成.

class C索尼音响: public 家电,

   public CComObjectRootEx<CComSingleThreadModel>,

   public CComCoClass<C组合音响, &CLSID_组合音响>,

   public IDispatchImpl<I组合音响, &IID_I组合音响, &LIBID_组合音响Lib>

{

   BEGIN_COM_MAP(C组合音响)

       COM_INTERFACE_ENTRY(I组合音响)

       COM_INTERFACE_ENTRY(IDispatch)

       COM_INTERFACE_ENTRY_IID(CLSID_组合音响, C组合音响)

   END_COM_MAP()

public:

   STDMETHOD(play)();

}

STDMETHODIMP 索尼音响::play(){

   ......

}

您可以看到, 为了这个 COM 的 Interface, VC++ 是如何大动干戈的了.

这么做的目的就是使得 VB 可以很方便地接上去:

 Dim 我的音响 as 家电库.索尼音响;

 我的音响.play

4. Delphi 中的 Interface

Delphi 1 开始的时候, 没有多重继承, 也没有 Interface, 还挺嘴硬: 多重继承容易出错.

以后为了支持 COM. Delphi 必须按照 MS 的规范实现了 COM Interface.

VC++ 是 C++, 必须遵守基本的 C++ 语法, 所以把 COM Interface 用template和宏来弄累极了.

Object Pascal 是 Borland 独家拥有, 想怎么定义自己觉得好就行. 所以 Delphi 3 的

Object Pascal 中始见如下写法:

type

 I组合音响 = interface;

 I组合音响 = interface(IDispatch)

   ['{621D2E6A-E5E5-4919-8230-2E2EAB3CB38x}']

   procedure play; safecall;

end;

T索尼音响 = class(TOleServer, I组合音响)

end;

class 后面的括号里可以写几样东西了.以前的 Turbo Pascal, Borland Pascal 可绝对不允许的.

这些东西就是 COM Interface. (导入/import type library 时自动生成)

Delphi 3, Delphi 4, Delphi 5 传了三代. 很多人对 Delphi 中的 Interface 认识仅限于此.

各位看官, 转眼到了 2001, 话说 Delphi 6 推出.我要郑重地告诉大家:

Delphi 6 中的 Interface 已经由单纯支持 COM Interface 的性质转变

到 Java Interface 的性质. 而已经完全是Design Patterns 中所定义的 Interface.

这是一场革命!

所以现在用 Delphi 6 做 COM/DCOM 用 Interface, SOAP 也用 Interface, CORBA 也用

Interface. 已经远不局限于 COM 了

我写得好累, 几次叉到如何调用 COM 的细节去, 又删掉回到 Interface 的主题.

终于写完了, 如有不妥, 敬请 cheka 等不吝指正.

来自:cheka, 时间:2001-9-15 14:29:00, ID:627629

佩服得说,我从来没有碰过Soap,对COM,Corba只是有些肤浅认识,就在语言方面

做点补充吧。

1. 关于 多重继承 和 接口 。

  事实上应该从继承说起,继承意味着子类具有父类所有的成员变量和成员方法,

(从本质而言,父类是作为子类的一个内嵌类存在的),那么多重继承也就意味

着子类具有好几个父类的所有成员变量及成员方法,这本身没有什么玄妙的地方,

但是一旦出现一种"菱形"结构, 即类 d1, d2 继承于类 b, 而类 mi 又多重继

承了类 d1,d2 ,则 mi 类中则会包含有两个 b 类的内嵌类,在做从 mi 到 b

的向上映射时,会出现二义性(C++ 用了一种虚继承的机制来避免这种情况)。

  我个人认为很多时候不应该把接口和多重继承放在一起谈,因为接口没有成员

变量,没有实现了的成员方法,它根本没办法作为另一个类的内嵌成员存在。也就

是说没有什么类可以"继承"接口,只有"实现"接口。

  写完上面的东西我中午出去溜达了一圈,买了本《COM本质论》(南京的朋友可

以在军人俱乐部内的科海书店用75折买到),先大概看了该书序言,里面一段话于

我心有戚戚,hoho,摘录这段话,希望不会被人告侵权:

"实际上应该存在两种继承性。实现继承(implementation inheritance )表示

真正的实现(即行为)被继承;而接口继承( interface inheritance )则表示

只有行为的规范被继承"

  以这个角度来理解的话,Java 和 Delphi 里的接口 还有 C++ 里的纯虚基类

都是提供了接口继承, 但是千万不要以为这是多重继承的替代,我想有必要强调这

一点: 只有在作向上映射时,接口才能发挥作用。

2. 关于 接口 和 设计模式            

 

  设计模式中关于接口的最最最最直观运用是 Adapter 即 适配器 模式,而

Adapter 在Observer 模式中也起到了相当重要的应用,强调这两个模式有两个原

  一, 这两个模式我最常用,也可以说别的模式我用得很少或者根本不会用。

  二, 我觉得这两个pattern 适合初学模式的入手,也很容易从中发现pattern

       及面向对象的妙处。

来自:LeeChange, 时间:2001-9-13 14:37:00, ID:623921

打个多重继承的比方:

 你有一个接口: I吃掉.他有一个方法(当然是虚拟的)叫 I吃掉.eat

 你还有两个类: T水果和T药,都实现了I吃掉接口.

 那么你就可以这样写程序

   AInterface:=AObjecct as I吃掉;

   AInterface.eat;

 程序自然会用正确的吃法去解决,而不管你的AObject是水果还是药

来自:cheka, 时间:2001-9-13 14:39:00, ID:623928

简单地说,接口就是一个纯虚类,没有任何实现

来自:kindly, 时间:2001-9-13 20:49:00, ID:624672

接口可以实现多重继承,举个图形方面的例子来说,可以定义IColor,IPosition,ISize,IDraw

这几个接口,然后再类中实现多重接口例如:

TMark=class(TInterfacedObject,IColor,IPostion,IDraw);

TSquare=class(TMark,IColor,IPosition,ISize,IDraw);

另外用接口写的东西可以不管你用什么语言都可以调用