现在的位置: 首页 > 综合 > 正文

从抽象到模式——面向对象之旅(一)、抽象的魅力

2013年11月22日 ⁄ 综合 ⁄ 共 2803字 ⁄ 字号 评论关闭

  最近一段时间,笔者设计了一款过滤器插件,用以对某系统的用户请求进行过滤,本系列文章即记载了整个过滤器插件开发过程中的一些面向对象设计的小事,一方面见证笔者对面向对象设计的一次探索,另一方面也是记录下来供大家一起学习和讨探。

  在本系列文章中,您将会看到我们是如何从最初的过滤器类的抽象,利用面向对象原则、设计模式等,一步一步将我们的项目重构成为最终看起来还比较“优雅”的样子。由于我们这里只讨论面向对象设计,因此我们将略过错误处理、异常以及具体的功能代码,同时为了便于理解,我们将适当简化一些函数的形参。

 

  下面大概说明一下这个过滤器插件的需求:

  1)如前所述,该插件将由系统在初始化时加载,用来处理用户请求。

  2)该插件由一系列过滤器(Filter)组成,这些过滤器用来验证访问授权、检查请求数据等等,每个用户请求都要依次通过这些过滤器的处理。

  3)每个过滤器都有一些过滤规则,它们分别保存在不同的文件当中,而且保存格式也略有不同。

 

  Ok. Every thing is ready. Let's begin.

  我们首先要设计的,当然是过滤器类。每个过滤器的功能基本相同,大概可以由两个函数组成,一个是读取规则:InitRules(),另一个是检查用户请求:CheckRequest()。

  因此,我们可以用一个抽象类来表示一个过滤器,如下所示(注意析构函数中的virtual):

  下面,我们将实现两个子类,它们是授权验证过滤器、数据检查过滤器:

  类已经写好了,下面我们要做的,就是应用这些类了。在插件类中,我们有如下代码:

  根据需求,我们需要有一个地方用来保存这些过滤器。因此,我们使用了一个vector来保存过滤器抽象类的指针。

  之后我们使用InitFilters()将过滤器添加到m_Filters中,并在InitFilterRules()初始化过滤器的规则。

  当用户请求到达时,系统会调用OnRequestCheck(),而这个函数要做的,就是遍历我们的过滤器,并执行CheckRequest()操作。 

  到目前为止,这个框架看起来还不错,我们有一个不错的过滤器抽象,客户代码只需依赖这一抽象接口,而不必关心底层的过滤器子类如何实现。如果要添加新的过滤器,其他代码都不需要做任何修改,只需要在InitFilters()函数中多加一行代码,这其中体现的便是面向对象的开放——封闭原则。

 

  开放——封闭原则要求“软件实体(类、模块、函数等等)应该是可以扩展的,但是不可修改的”。开放是指对于扩展是开放的,即模块的行为是可以扩展的;而同时对于更改是封闭的,即对模块行为进行扩展时,不必改动模块的现有代码。

  而这二者的实现需要可以创建出固定的且能够描述一组任意个可能行为的抽象体,这个抽象体就是抽象基类。而这一组任意个可能的行为则表现为可能的派生类。由于模块依赖于一个固定的抽象体,所以它对于更改是关闭的。同时,通过从这个抽象体派生,便可以扩展此模块的行为。

  开放——封闭原则是面向对象设计的核心所在,而这其中抽象发挥着关键的作用。

 

  同时,我们还要注意到,抽象类与它的客户的关系要比实现它的子类的关系更密切一些。这里引申出的另一个原则便是依赖倒置原则:“高层模块不应该依赖于低层模块。二者都应该依赖于抽象。抽象不应该依赖于细节。细节应该依赖于抽象。”

  面向过程的开发方式中,人们总是倾向于创建一些高层模块依赖于低层模块、策略依赖于细节的软件结构。然而,当变化来临时,尤其是低层结构发生变化时,整个软件结构的将呈现出链条式的变化,所有依赖于该低层模块的高层模块都要依次做修改以应对变化,这是面向对象所不希望看到的。

  因此,面向对象思想希望能够重用的是高层的策略模块,他认为包含高层业务规则的模块应该优先于并且独立于包含实现细节的模块。那么,这又是如何做到的呢?

  首先,每个较高的层次都为它所需要的服务声明一个抽象接口,较低的层次实现这些抽象接口,而高层接口则通过这一抽象接口使用下一层。这样高层就不再依赖于低层,低层反而依赖于高层中声明的抽象服务接口,从而实现的依赖的倒置,所以我们可以说这里的倒置是指程序结构相对于传统的面向过程的设计方法而言是倒置的。

     依赖倒置原则是面向对象区别于面向过程的标志所在,如果程序的依赖关系是倒置的,它就是面向对象的设计;否则,它就是过程化的设计。依赖倒置原则是实现面向对象技术的基本低层机制,它的正确应用对于创建可重用的框架来说是必须的。同时它对于构建在变化面前富有弹性的代码也非常重要。

 

  关于抽象就先到这里为止了。在第二节,让我们看看当读取规则的时候会发生什么。

【上篇】
【下篇】

抱歉!评论已关闭.