面向对象的设计原则之一:针对接口编程,而不是针对实现编程 (100分)

  • 主题发起人 主题发起人
  • 开始时间 开始时间

Unregistered / Unconfirmed
GUEST, unregistred user!
针对接口编程,而不是针对实现编程
在面向对象设计方法中有很多值得提倡的方法,这些方法可以为我们的设计带来很大的灵活性,可复用性。其中一个原则就是“针对接口编程,而不是针对实现编程”
这个原则带来的好处有以下几点:
Client不必知道其使用对象的具体所属类。
Client无需知道特定类,只需知道他们所期望的接口。
一个对象可以很容易地被(实现了相同接口的)的另一个对象所替换。
对象间的连接不必硬绑定(hardwire)到一个具体类的对象上,因此增加了灵活性。
松散藕合(loosens coupling)。
增加了重用的可能性。提高了(对象)组合的机率,因为被包含对象可以是任何实现了一个指定接口的类。
在实现上:
C++通过继承纯虚类来实现接口继承。
Java对接口继承具有单独的语言构造方式-Java接口。
但从辩证法的角度看,事物总有利有弊。“针对接口编程”有如上诸多好处,确不可避免的带来设计的复杂性。特别对于没有丰富经验的设计人员。
其中令我比较困惑的地方是:
要想针对接口编程,就必然要最大化接口类,使包括所有子类的方法,这样我们才能利用多态性用接口类来一致的操作子类。但这会带来以下几点不足。
违反面各对象的另一个原则,这个原则是:一个类只能定义那些对它的子类有意义的操作。
接口类包括了并不是对每一个子类都有意义的方法,使接口类臃肿,难以理解。
从父类继承的无用方法,如何处理。
举个例子来说。我们要实现这样一个功能模块。一个TreeView上有各种节点。我们对这样的一个Tree 的节点操作。比如复制,剪切,粘贴,重命名,查看属性、设置它的图标,添加到树节点上等等。每种节点的相同操作(比如复制)的实现是不同的。
你会怎么设计它:
在C++中我会这样做。
我会将每种结点实现成一个类。以实现各自的相关操作(比如复制,粘贴),这些类都继承至一个纯虚的父类,在这个父类中以虚方法的方式声名子类实现我的相关方法,这样做的好处是当你从Tree中取出一个节点时,你不必关心这个节点是什么类实现的,你只需要以纯虚的父类指针操作它就可以了,这样就实现了接口继承的所带来的优点。
但是,如果并不是每个节点都支持所有的方法,比如有些节点不允许复制,有些节点不允许重命名等,那么从父类继承的声名如何处理,实现成一个空方法么?还是不将这样的方法放到父类中?如果不放到父类中,就没办法以统一的方法操作所有的子类了!
请大家就这个问题畅所欲言。分不够我还可以加,虽然本人比较穷,但仍可倾囊相赠!
 
那就不要那么麻烦吧,你定义节点的类型,然后在接口实现时判断节点类的类型进行相应的代码实现,不然就只有加空方法了,关注看有没高招
 
可以使用接口继承来划分不同节点的操作
type
INodeA = interface(IInterface)
procedure copy;
end;

INodeB = interface(INodeA)
procedure paste;
end;
不同的节点类实现不同的接口
 
Windows的许多高级编程功能都是用接口实现的,而且这些接口对以后的使用和再开发都有很大帮助。我是比较喜欢接口编程的。当然,做接口的时候是很麻烦的。
 
TO liuxi
能否在详细些?
 
还是上面的例子
type
INodeA = interface(IInterface)
procedure copy;
...
end;

INodeB = interface(INodeA)
procedure paste;
...
end;

TNodeA = class(TObject, INodeA) // TNodeA 实现 INodeA
public
procedure copy;
...
end;

TNodeB = class(TObject, INodeB) // TNodeB 实现 INodeB
public
procedure copy;
procedure paste;
...
end;

这样做强制使用 INodeA 来操纵 TNodeA 类型的节点,INodeB 来操纵 TNodeB 类型的节点。
不要试图使用 INodeA 来操纵 TNodeB 类型的节点,这将导至一个错误。虽然 INodeB 继承
自 INodeA,但 TNodeB 类型的节点并不直接支持 INodeA 接口(如果类实现了接口的话,那
它的实例对应一个接口表,接口表中的每个接口对应一个接口方法表,在 TNodeB 类型的节
点并没有实现 INodeA,因此在 TNodeB 实例的接口表中无法查找到 INodeA 接口,所以会产生一个错误)。
 
楼主,接口继承是针对接口编程中很重要的一块,去看看COM的书,对你了解接口编程会有帮助的。
 
接口的難題就是定義一個好的,合適的接口.
 
liuxi的方法就达不到版主的要求了
 
这就是COM,COM+,今后的NET也属于此类吧!
 
这种和接口屁边不着的问题,硬要拖来和接口沾边做什么?
Microsoft 实现的 Treeview 的操作和节点类并不定义在同一个类中,也没有 COM 化。
 
to flamingo
连这种问题都看不懂,看来我没必要和你一般见识!
 
我当然看不懂。一会儿说接口,一会儿又说接口类。谁懂,站出来告诉我,我准备五体投地的说。
 
我的个人理解,接口只是公开的调用方法,可以比喻为dll中的函数或过程,你只需知道调用
什么dll中的什么函数和过程就可实现什么功能即可,无须了解实现细节。从写接口的方面说
你只要按照接口定义的函数和过程写好实现细节,给别人调用即可。简单的说dll也是一种接口。
所谓接口类,就比接口更加高级,就好比dll和类库的比较一样。dll中只指定了某些关连的函数
或过程;而类则可以继承可以进行更多的接口组合,所以接口类比接口更加重要。
如果写过IE接口或底层的THookCopy接口之类的代码后,应该能够很佩服接口的编程理念的。
至少我是这么认为的。
呵呵,一点个人拙见,见笑见笑!
 
忘了说了,上面只是对接口的一种比喻,不是说接口就等于dll啊!
 
害我无端地在这个论坛等了 3 天,回答了 10 多个无聊的问题,还是没等到谁来给我解释
什么叫接口,什么叫接口类,这个论坛真衰,恕不奉陪了。
 
接口interface,是COM机制一个重要部分,用什么方法来访问一个类的方法,至少有:
1. 创建一个实例,通过此实例来访问
2. 通过接口
其实这只是一种改良版的DLL机制!
---------------------
关于"...就必然要最大化接口类...",在下认为充分利用abstract, virtual, dynamic, override还是可以创建出比较理想的架构的!
你可能得根据每个NODE的不同方法集而设计不同的子类,子接口了,我想你的判断多态实例创建时应该在TREEVIEW实现,对不同NODE创建不同的对象...愚见~~~
 
.net 的发展 会包容 com+ ??
 
搬个板凳来听课,嘿嘿。。。
 
后退
顶部