.net你必须知道的事儿 1.4

翻开大部头的韦氏大词典,关于多态的定义为;可以呈现不同形式的能力或状态,这一术语来源于生物系统,意指同族生物具有的相同特征。而在,net中多态指同一操作作用于不同的1实例,产生不同的运行结果的机制,继承,封装和多态构成面向对象的三要素,成就了面向对象编程模式的基础技术机制。在本节,我们以入情入理的小故事为线索,来展开一次关于多态的循序渐进之旅,在故事的情节中思考多态和面向对象的艺术品质。

既然是个独立的应用系统,小王就分析了万能加载器应有的几个功能点,小结如下;自动加载各种资料,一站式收缩系统常见资料

能够打开常见文档类资料,

 

 小王按照构思的系统框架,首先构思了可能打开的最常用的文件,并将其设计为一个枚举,这样就可以统一来管理文件的类型啦,实现如下

 

 

看着这个初步设想的文件类型枚举,小王暗暗觉得真不少,如果在增加一些常用的文件类型,这个枚举还真是气魄不小呀。

有了要支持的文件类型,小王首先想到的就是实现一个文件类,来代表不同的文件资料,具体如下

 

 接着小王按照既定思路构建了一个打开文件的管理类,为每种文件实现器具体的打开方式,列如

 

 

哎呀这个长长的单子还在继续往下写,openjpgFile,OpenGifFile,OpenMP3fILE,OPENaVIfILE---不知要到什么时候。

上一步着实让小王步履维艰,下一步的实现更让小王濒临奔溃了,在系统调用端,小王实现的文件加载器是被这样事实现的;

 

 

 

 完成了文件打开的调用端,一切都好像上了轨道,小王的万能文档器也有了基本的架子,剩下再根据实际需求做一些调整即可,小王新虫虫的见自己的作品那个爷爷看,却发现爷爷正在想打开一段rm格式的京剧听听,但是小王的系统还没有支持职业文件格式,没办法只好回球继续修改了。

需要深度调整客户端,为系统维护带来麻烦,况且我们因该尽量白保持客户端的相对稳定,

word,pdf,MP3等都是可以是想的独立对象,整个系统除了有文档管理了几乎没有面向对象的影子,群不都是面向结构和过程的开发方式

在实现打开文件陈程序时小王发现其实OpenDocFile有很多重复的方法

由于系统之间没有分割,没有规划,整个系统就像一堆乱码几乎不可能完成任何简单的扩展和维护

任何修改都会将整个系统犀利一次修改遍布全系统的整个代码,并且全部重新编译才行。

需求变更时结果后化设计的大敌,无法轻松完成起码的系统扩展和变更,列如再打开这一操作之外,如果实现删除,重命名等其他操作,对当前的系统来说将是致命的打击,在发生需求多变的惊天,必须实现能够灵活扩展和简单变更的设计构思,面向对象是灵活设计的有效手段之一

看着经不起考验的系统,经过了短期的郁闷和摸索,小王终于找到了阿里巴巴不倪安东芝麻开门的魔咒,多态

,欸错多态就是面向对象的这是小王痛定思痛后翻出的有种感慨,小王再接再厉颠覆了原来的构思,一个新的设计宽假氤氲而生如图1-12所示

结合新的框架,比较值钱的别叫设计小王提出了新系统的新气象主要包括以下几处修改

将word,pdf等业务实体抽象为对象,并在每个相应的对象内部来处理本对象类型的文件打开工作,这样各个类型之间的交互操作就被分离出来,这样很好的体现了职责单一的员的目标

 

 将各个对象的属性和行为相分离,将文件打开这一行为封装为接口,再由其他类来实现这一接口,有利于系统的扩展同时减少了类鱼类的依赖。

将相似的类抽象出共共的基类在积累中实现具有共性的特征,并由子类继承父类的特征,类如word,pdf,txt的基类可以抽象weiDocLoader 而而jpg和gif的基类可以抽象为imagelodaer,这种实现体现的是面向对象的开放封闭原则,对扩张开放,对修改关闭,如果有性的类型需要扩展,则只需继承合适的基类成员,实现型类型的特征代码i即可。

实现可柔性扩展的接口机制,能够更加简单的实现增加新的文件类型加载程序,也能够哼好的扩展打开文件之外的其他操作,列如删除,重命名等修改操作

实现在不需要调整原系统,或者很少调整原系统的情况下,进行功能扩展和优化,甚至是无须编译的插件式系统

下面是具体的实现,首先是通用的接口定义

 

 接着定义所有文件类型的公共基类,因为公共的文件基类是不可以实例化的,在此处理为抽象实现会更好,详细为

 

 基类Files实现了IFileOpen接口,不过在此仍然定义方法为抽象方法,除了文件打开抽象方法,还可以实现其他的通用文件处理操作,列如文件删除delete,文件重命名Rename和获取文件路径等,有了文件类型的公共基类,是时候实现其派生类了经过一定的分析和设计,小王没有马上提供具体的资料类型类,而是对派生类型做了归档,初步实现文件类型,图片类型和媒体类型三个大类,将具体的文件类型进一步做了抽象;

 

 

 

 终于是实现具体资料类的时候啦,在此以word类型为例来说明具体的实现;

 

 

 

 其他类型的实现类似于此,不同之处在于不同的类型有不同Open实现规则,以应对不同资料的打开操作,小王根据交媾的设计,同时提供了一个资料管理类来进行资料的统一管理

 

 

 

 

 

 当然现在的FileLoader客户端还有很多要完善的工作要做,列如关于文件加载的类型,完全可以定义在配置文件中,并通过抽象工厂模式和反射于运行期动态获取,以避免耦合在客户端,不过基本的文件处理部分已经能够满足小王的预期。

谁徐耳边的业务

爷爷机子上的资料又增加了新的视频文件MPEG,原来的AVI文件都太大了,可是这回根本就没有难倒小王的万能加载器,在电脑前折腾30分钟后,万能加载器就可以适应新的需求,图1-13所示的是修改的框架设计。

 

 

 

 按照这个新的设计,小王对系统只需要做如下的简单调整吗,首先是增加处理MPEG文件的类型MPEGFile并让他继承子MediaFile实现昂具体的Open方法即可

 

 

 

 接着就是添加处理新文件的加载操作,

ok添加新类型的操作就此完成,在没有对原系统进行修改的基础上,只需加入简单的类型和操作即可完成原来看似复杂的操作·1,结果证明新架构经得起考验,爷爷也为小王竖起了大拇指,事实证明,只要又更合理的设计与架构,在基于面向对像和.net框架的基础上,完全可以实现类似于插件的可扩展系统,并且无需编译即可更新扩展。

这一切是如何神奇般的实现了呢,回顾从设计到实现的各个环节,小王深知这都是源于多态机制的神奇力量,那么究竟什么是多态。net中如何来实现多态呢?

多态的类型,本质和规则

从小王一系列大刀阔斧的改革中,我们不难发现是多态,是面向对象技术成就了FileLoader的强大于灵活,回过头来, 结合FileLoader系统的实现分析,我们也可以从技术的角度来进一步探讨关于多态的话题。

多态的分类

多态又多种分类的方式,luca cardelli在中将多态分为四类,强制的,重载的,参数的和包含的,本节可以理解为包含的多态,从面向6对象的角度来看,根据实现的方式我们可以进一步分为基类继承多态和接口实现多态

基类继承式多态

基类继承多条的关键是继承体系的设计于实现,在FileLoader系统中File类作为所有资料类型的基类,然后根据需求进行逐层设计,我们从架构设计图中可以清楚的了解继承体系关系,在客户端调用时,多态是以这种方式体现的

 

 

myFile是一个父类Files变量,保持了指向子类wordfILE实例的引用,然后调用一个虚方法Open,而具体的调用则决定于运行时而非编译时,从设计模式角度看,基类继承式多态体现了一种is-a方式,列如wordfile is-a files就体现在这种继承关系中

接口实现式多态

多态并非仅仅体现在基于基类继承的机制中,接口的应用同样能体现多条的特性,区别于基类的继承方式,这种多态通过实现机口的方法约定形成继承体系,具有更高的灵活性,从设计模式的角度来看,接口实现多态体现了一种can-do关系,同样,在万能加载器的客户端调用时,也可以式这样的实现方式;

 

 

 当然,很多时候这两种方式都是混合应用的就像本节的FileLoader系统的实现方式。

多态的运行机制

从技术实现角度来看,是.net的动态判定机制成就了面向对象的多态特性,那么社么是动态绑定,.net又是如何实现动态绑定呢,这就是本节关于多态的运行机制所要探讨的问题。

动态绑定,又叫晚期绑定,是区别于静态绑定而言的,静态绑定在编译期就可以确定关联,一般是以方法重载来实现的而动态绑定则在运行期通过检查虚拟方法表来确定动态关联覆写的方法,一般以继承和虚方法来实现,zai.net中 虚方法以virtual关键字来标记,在子类中覆写的虚方法则以override关键字标记,从设计角度考量,通常将子类中公有的但却容易变化的特征抽取为虚函数在父类中定义,而在子类中通过覆写来重新实现其操作。

严格来说。net中并不存在静态绑定,所有的,net源文件都首先被编译为IL代码和元数据,在方法执行时,IL代码才被JIT编译器即时转换为本地CPU指令。JIT编译发生于运行时,因此也就不存在完全在编译期就建立的关联关系,静态绑定的概念也就无从谈起,本文此处

 关于。net通过什么方式来实现虚函数的动态绑定机制,祥细情况请参阅本章1.2节“什么是继承的详细”在此我们提取万能加载器FileLoadaer中的部分代码来深入分析通过虚方法进行动态绑定的一般过程;

 

 

在继承体系的实现基础上,接着是客户短的实现部分:

Files myFile=new WORDFile();

myfile.open()

针对上述示例,具体的调用过程,可以小结为

编译器首先检查myFile的声明类型为Files,然后查看myFile调用方法是否被实现为虚方法,如果不是虚方法,则直接执行即可,如果是虚方法,则会检查worddFile是否重写该方法Open,如果重写则调用wordfile类中覆写的方法列如本例中就将执行wordfile类中覆写过的方法,如果没有重写,则向上递归遍历其父类,查找是否覆写方法,直到找到第一个覆写方法调用才结素。

多态的规则和意义

多条提供了对同一类对象的差异化处理方式,实现了对变化和共性的有效封装和继承,体现了一个一个接口,多种方法的思想,使方法抽象机制成为可能。

在.net中,默认情况下方法是非虚的以c#为例必须显式的通过virtual或者abstract标记为虚方法或者抽象方法,以便在子类中覆写父类方法

在面向对象的基本要素中,多态和继承,多态和重载存在紧密的联系,正如前文所述多态的基础就是建立有效的继承体系,因此继承和重载式多态的实现基础。

 

posted @ 2020-08-15 14:24  ZELDA小菜鸟  阅读(157)  评论(0编辑  收藏  举报