版权所有:nicrosoft
文章来源:东日制作室
多态性,是一种能给程序带来灵活性的东西。看过《设计模式》的程序员应该都知道,相当多的模式(几乎所有)都是依靠多态来实现的,以此给程序提供可扩展、可重用性。在《再谈多态——向上映射及vmt/dmt》一文中,提到了多态性是依赖于虚函数/虚方法(即动态绑定)来实现的,也介绍了虚函数/虚方法(virtual)的实现方法。那么本文就来谈一下,如何使用virtual、善用virtual来获取多态性给我们带来的灵活性。
实例是最好的教材,因此本文还是假设一个需求,写一个实例来讲解。不过,我想没有必要给出所有源码,因此在本文中有些实现的代码会粗略带过。另外,本文所有代码均为object pascal语言编写,实现环境为delphi。
另外,由于“方法(method)”一词已经成为object pascal的术语,因此,以下称成员函数都为“方法”。也许c++程序员会不太适应这样的称呼(呵呵,我自己也不太适应),见谅吧。
假设我们要编写一个纯文本内的编辑器,也就是记事本(呵呵,别嫌例子老套,记事本程序在相当多方面都是很好的教材),编辑控件我们一般会用tmemo或trichedit,但是它们的功能都不甚强大,也许我们目前没有,但日后会找到一个更好的第三方文本编辑控件(比如,支持语法着色的)。因此,我们必须为未来的改进留下方便之门,否则到时候再重写全部程序真是太傻了。
界面层(菜单响应、状态显示等)对文本编辑器控件的控制的代码对于所有编辑器来说都是类似的,应该可以被重用。那么就必须将界面层的代码与编辑器控件的控制代码隔离开来。
如何隔离?我们可以为所有的编辑器控件指定一个公共的接口(抽象类),界面层只看得到这个接口,只使用接口提供的功能,那么,我们更换任何编辑器控件时,都不必更改界面层的代码了。
首先,抽象出编辑器的基本操作,如:load(打开文本)、save(保存到文件)、copy(复制到剪贴板)等等,将这些操作作为public方法。其次,考虑这些操作中有哪些会涉及到具体相关控件的,对于这些操作,你有两种选择:1、如果完全依赖控件本身的,可以选择将其定义为虚方法或抽象虚方法(即c++中的纯虚函数);2、如果只是有部分代码依赖控件本身的,将这部分操作抽象到一个protected的抽象虚方法中,而将相同的部分代码写在基类中,并由基类的方法中调用protected的抽象虚方法。
如果还没有完全明白,请看代码:
teditor = class // 抽象基类
private
m_filename : string;
protected
function doload(filename : string) : boolean; virtual; abstract;
public
function load(filename : string) : boolean;
function save() : boolean;
function saveas(filename : string) : boolean; virtual; abstract;
// ... 其他需要的操作,由需求而定
end;
好,我们来详细说明一下teditor为什么是这个样子的。其有一个私有成员,保存编辑器所对应的文件名。然后看public部分,它至少提供了三个操作:load——从某文件中读取文本到编辑器;save——将文本保存到文件,文件名为m_filename所保存的;saveas——以指定的一个文件名保存文本。
三个操作中,saveas为抽象虚方法,因为它的实际动作与每个编辑控件相关,而基类本身并不知道该如何保存文件。
save和load都是非虚方法,其中save的任务很简单,就是将文本以m_filename所保存的文件名保存,其实现可以是调用抽象的saveas,只需要将文件名传给saveas即可。基类完全可以确定如何完成save(因为它可以保证派生类实现了saveas),因此其为非虚方法。
而load呢?load操作的步骤是:1、将文本从文件中读取到编辑器控件中;2、将m_filename的值设置为所读取的文件名。其中第一个步骤与具体编辑器控件相关,应该是由派生类去实现它,第二个步骤派生类无法实现,因为派生类看不到私有的m_filename成员。但即使把m_filename移到protected节中,以使派生类可以访问它,也并非好办法,因为这样的话,在实现每个派生类时,都要记住设置m_filename的值,这不仅造成代码重复(每个派生类都要这样做),而且这不应该是派生类的义务。因为m_filename应该是基类的内部实现,对外不可见。因此,第二个步骤应该由基类来完成。如何达成这个目的呢?
Java Asp PHP .Net XML C/C++ CGI VB Jsp J2ee J2se J2me EJB Servlet Tomcat Resin Struts Weblogic Eclipse ANT GUI JMS Web servise IDEA Webphere Hibernate Spring Jboss Applet Swing Socket Javamail Perl Ajax P2P 安全 模式 框架 测试 开源 游戏
Windows XP Windows 2000 Windows 2003 Windows Me Windows 9.x Linux UNIX 注册表 操作系统 服务器 应用服务器