浅谈Chromium中的设计模式--二--pre/post和Delegate模式

Pre/post

请注意pre/post不能算是典型意义上的设计模式,Pre/post是契约式编程思想的概念。但是在从chromium代码中确实能看到不少他们的身影。

契约式编程中的PRE/POST

契约式编程(英语:Design by Contract,缩写为DBC)在Wiki上的解释:契约式编程是一种设计计算机软件的方法。这种方法要求软件设计者为软件组件定义正式的,精确的并且可验证的接口,这样,为传统的抽象数据类型又增加了先验条件、后验条件和不变式。这种方法的名字里用到的“契约”或者说“契约”是一种比喻,因为它和商业契约的情况有点类似。

在《程序员修炼之道:从小工到专家》中专门有一条讲的就是契约式编程(按合约设计)。

DesignbyContract的核心是断言(assertion)。所谓“断言”,是指永远为真的布尔型语句,如果不为真,则程序必然存在错误。通常情况下,检查断言的时机,应该局限于调试(debug)阶段,而不是代码的实际执行阶段。实际上,完成的程序永远不应期望断言会被检查。

DesignbyContract使用了三类断言:后继条件(post-conditions),前提条件(pre-conditions),以及不变量(invariants)。其中前驱条件与后继条件都是针对操作(operation)而言的。

前提条件preconditions:acondition that must hold up on invocation of a function在方法被调用之前就必须满足的条件。

后继条件post-conditions:acondition that must hold up on exit from a function法被调用之后所要保持的条件

不变量invariants:acondition that must always hold for objects of the class,except while a public member function is executing.在方法的执行过程中,不变量可能为假,但是,在其他任何对象能够与被调用方进行交互的时刻,不变量断言必须恢复为真。

在之前MBT的探索中,我们曾经尝试使用了PRE/POST模型,可参考文章http://tmq.qq.com/2016/11/pre_post_explore/。

Chromium中的PRE/POST代码设计

虽然c++11不支持contract的语法,但是从chromium的代码上也可以看到代码也采用了pre/post的方式来设计。

我们可以从chromium的启动代码中看下pre/post思想是怎么使用的。

下图是Chromium中浏览器启动时候的代码顺序:

具体函数调用可以参考网上文章(http://blog.gclxry.com/chromium-framework-start/)。

启动的主要逻辑都是在Browser Main RunnerImpl,可以看到下面这段函数也是典型的pre/post的设计:

上面函数在main_loop_->Main Message Loop Start之前, 先调用main_loop_->Pre Main Message Loop Start准备相应的环境, 在执行完main_loop_->Main Message Loop Start之后又调用main_loop_->Post Main Message Loop Start来做后置条件的相关操作。

在每个layer里面都有对应的pre/post代码:

Browser MainLoop 里面的Pre Main Message LoopStart 又会调用对应的平台的Chrome应用(_parts对应的就是Chrome Browser Main Parts,不同的平台的应用不一样,windows上面就是Chrome Browser Main Parts Win)的Pre Main Message Loop Start。

在Chrome Browser Main Parts里面Pre Main Message Loop Start又会调用chrome_extra_parts_(多个扩展应用Chrome Browser Main Extra Parts:其中Chrome Browser Main Parts是对应的平台,

Chrome Browser Main Extra Parts是对应不同的Chrome toolkits (e.g., GTK, VIEWS, ASH, AURA, etc.))的Pre Main Message Loop Start。

PRE/POST设计的好处

在编程语言不支持了DBC的情况下,在代码层面采用PRE/POST的设计可以极大地提高代码的易读性和可维护性。且建立这种契约明确了我们什么时候什么阶段该干什么事。

Delegate模式


Delegate模式介绍

维基百科的解释:委托模式是软件设计模式中的一项基本技巧。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。委托模式是一项基本技巧,许多其他的模式,如状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式。委托模式使得我们可以用聚合来替代继承,它还使我们可以模拟mixin。

Delegate在chromium中的使用

Chromium是一个复杂的开源项目,其中应用了丰富的设计模式来组织代码,应用最广泛的应该算是Delegate Pattern(委托模式)。

在chromium中,每个模块具体功能的实现基本上都是通过Delegate类来实现的,如果开发者继承该Delegate类,并加以实现就能很方便的完成定制,倘若开发者不需要某个模块的功能,也就不用实现相关的Delegate类,那么该模块就不会发挥效用。

Delegate的使用使得自动化测试也非常容易,这些测试需要能直接检测Chromium中的某个特性或功能能不能正常工作,检查新添加的代码对原有的代码有没有影响,但是由于有些功能需要手动干预才能正常工作,比如下载模块中弹出的对话框需要手动选择保存文件的地址和文件名;这些会给自动测试代码带来麻烦,但是有了delegate的设计,我们在测试代码中可以直接实现对应的Test的delegate,继承正常工作的delegate,该类做一些简单的修改事先填好一些数据,从而绕开需要手动输入代码块的执行。这就一方面完成了对已有代码的测试,也同时兼具了自动化。

Chromium中Delegate模式的例子

在Chromium项目中有个Download Manager类(content里面),它负责完成任务的下载功能,当在浏览器中点击某个不能被渲染的链接时,浏览器就认为该链接的文件需要下载,就通过Download Manager来完成下载流程。

当在浏览器中点击某个不能被渲染的链接时,浏览器就认为该链接的文件需要下载,就通过Download Manager来完成下载流程。但是下载文件的实际工作都是在Download Manager Delegate中完成的,比如选择文件的路径,检查文件路径名是否合法,下载时候完成之类等。开发者只需要自己设计一个新的Delegate类来继承Download Manager Delegate,并覆盖相应的方法即可完成下载功能,另外需要通过Set Delegate方法,在程序开始时把自定义类的对象注册到Download Manager中。目前Chrome,Content Shell,CEF3和Crosswalk都有自己的实现。

Chrome基于Download Manager Delegate的UML类图:

下面看看自动化测试中应该怎么使用设置test的delegate:

首先,基于Chrome Download Manager Delegate实现自己的测试的delegate:Delaying Download Manager Delegate。

上面代码就是基于Chrome Download Manager Delegate定义了测试所需要的Delaying Download Manager Delegate类,并重写了方法Should Complete Download 这样就可以绕开真实的delegate里面复杂的Should Complete Download逻辑判断,并简单的返回了false来进行测试。

在对应的测试用例代码里面调用set Delegate替换为测试的delegate。

定义完了测试的delegate类,调用SetDelegate来使得Delaying Download Manager Delegate生效。

    • *

长按指纹识别图中的二维码,获取更多测试干货分享!


Original url: Access

Created at: 2018-09-30 13:50:02

Category: default

Tags: none

请先后发表评论
  • 最新评论
  • 总共0条评论