神刀安全网

设计模式在UI系统开发中的应用(导读)

整理硬盘,发现了2012年撰写的内部培训PPT教程。
当时主要从事UI方面的工作,并且负责公司内部培训,因此为了培训相关开发人员,特意编写了一个基于windows 的C++ UI库(当时移动尚未如此之火热,虽然是win32,但是思想是一样的,可以用于任何系统),用于演示UI的核心概念以及面向对象设计模式相关的内容。

面向对象和设计模式的作用是什么?

我个人认为就是: 通过面向对象,设计模式等思想或手段形成一种机制:封装不变的部分,将可变的部分以虚函数或事件回调等方式公开给调用方。

面向对象教程分为:面向对象需求分析, uml基础及用法,实现一个复杂控件三部分组成(建立在设计模式实现的类库上,等设计模式好了后,再开源)

设计模式教程由六个部分程序组成

设计模式在UI系统开发中的应用(导读)

设计模式代码库.png

UIPLib.lib(核心库)

UI的核心是什么?

我个人将其归纳为: “一个中心,四个基本点”

一个中心: 以树数据结构(控件树)为中心

四个基本点: 控件的布局、控件的事件分发及处理,控件的脏区局部刷新、控件的渲染

控件的布局/事件/刷新/渲染都是建立在控件树不同的遍历基础上的。

由此可知,UIPLib的功能就是实现上述的“一个中心,四个基本点框架“功能。

之所以说是框架,是因为它建立了一套机制,但是实际使用需要从该机制对应的各个基类进行继承实现。具体我们会在后面看到。

将不变的部分封装在类库中,将可变部分声明为虚方法,由继承者来进行override,从而达到天人合一之境。

设计模式在UI系统开发中的应用(导读)

内容2.png

 1. 容器用到的设计模式:适配器/迭代器/策略/装饰
  • ArrayList.h 中实现了泛型的动态数组,类似std::vector或js中的Array对象

  • Iterator.h 中主要定义了迭代器模式和线性列表的遍历方向策略(从左到右,从右到左)

设计模式在UI系统开发中的应用(导读)

迭代器.png

设计模式在UI系统开发中的应用(导读)

线性遍历策略.png

  • Node.h 中定义了基类CNode以及CTypeNode 泛型类,所有子类,请继承自CTypeNode类

  • NodeIterator.h中定义了树节点线性迭代需要的相关内容

设计模式在UI系统开发中的应用(导读)

树节点遍历.png

设计模式在UI系统开发中的应用(导读)

遍历之间的关系1.png

设计模式在UI系统开发中的应用(导读)

遍历之间的关系2.png

设计模式在UI系统开发中的应用(导读)

遍历之间的关系3.png

之所以花这么多力气来解释树的遍历,是因为其重要性,树结构可以说是我用的最多,最强大的数据结构。一定要掌握他!

UIPText.exe程序中,进行了8个迭代器的测试:

设计模式在UI系统开发中的应用(导读)

nodeIteratorTest.png

设计模式在UI系统开发中的应用(导读)

迭代测试结果.png

2.  ControlSystem用到的设计模式:组合及模板方法
  • 在这个部分中,使用了结构型设计模式-组合(其实树结构就是经典的组合模式)以及模板方法的模式。

  • 通过ControlSystem系统,建立一个自定义控件的插件体系
    后面看到的UIPControl.lib就是具体控件的实现,而UIPLib中的ControlSystem定义的是共性部分。典型的插件方式。

  • 通过ControlSystem提供CControlBase基类,你可以继承CControlBase并实现自己的控件,然后可以将一个控件组成一个插件lib,或者一系列控件组成一个插件lib,进行链接导入,灵活性大增,后面会了解如何使用的。

  • ControlManager是Control的根节点,也是控件布局/事件分发/局部刷新/渲染的起始节点!!

    3. 事件系统用到的设计模式: 观察者
  • 使用开源的FastDelegate库,并在FastDelegate基础上增加了多播功能(实际就是实现了C#的delegate功能),并支持触发顺序的调整(其实该实现源码来自于Torque3D Engine)

  • 和C# 事件类似的系统,对于自定义事件,只需如下:

设计模式在UI系统开发中的应用(导读)

自定义Render事件.png

定义好三者,注册事件处理函数,可以在任意地方触发事件,在任意地方,以全局函数,成员方法或静态方法等方式进行回调,超级好用的类C#事件系统

  • 这里用到的观察者模式和书上的经典描述有差别,因此在UIPTest.exe中实现了一个经典版的观察者模式,可以调用看看结果。并且在教程中分析了Java awt中的事件监听方式。

  • 对C# delegate事件体系的扩展:Document Object Model (DOM) Level 3 Events Specification

关于该事件系统(也就是经典的冒泡事件系统),我是非常喜欢的。因此在后来,我花了点时间,研究webkit相关源码,从中剥离出干净代码移植到的代码中。

其实DOM Event事件系统依赖如下几个特点:
1) 需要一个树结构—-已经具有控件树了
2) 需要事件监听优先级—-在FastDelegate基础上实现了根据权重调整触发的先后顺序
3) DOM Event事件支持多播触发—-在FastDelegate基础上实现了多播功能
4) 冒泡与和捕抓—-需要自己实现,我们只要实现这个就可以了
其实冒泡事件的使用是很有技巧的,用的好的话,是很令人愉悦的体验。

关于冒泡事件,并没有在本系列教程中,如有需要就自己扩展一下

4. 渲染系统用到的设计模式:工厂方法
设计模式在UI系统开发中的应用(导读)

渲染系统.png

  • 面向接口编程,使用工厂方法返回接口
  • 实现了GDI 渲染器,很容易扩展到其他渲染backend.
  • 将结果渲染到IRenderImage中,然后bitblt到显存,通过这种方式(双缓存)避免闪烁
  • 使用渲染到纹理(IRenderImage),有利于应用于3DAPI中,例如opengl/directX。
5.脏区局部刷新用到的设计模式: 模板方法
  • 因为使用windows,所以使用了windows自有的InvalidateRect API进行脏区标记,用于触发重绘
  • 如果使用各自系统的控件体系,基本都有自己的脏区标记函数,例如android中的invalidate方法,ios中的setNeedsDisplayInRect方法,这些API都可以指定一个rect,需要重绘的地方限制在该rect中。
  • 关于脏区的使用:
设计模式在UI系统开发中的应用(导读)

脏区检查.png

  • CControlBase的Render方法规定了调用的流程:
设计模式在UI系统开发中的应用(导读)

render模板方法.png

  • 由此可见,子类override OnXXXRender时,必须要先调用基类相同名称的方法才OK。
    例如UIPControl.lib中自定义的控件的OnRender方法的override必须要要调用基类同名方法
设计模式在UI系统开发中的应用(导读)

例子.png

  • 关于脏区重绘,是个很好玩的领域,是2D游戏或UI引擎性能提高的关键要素。在这个部分,我有过一定的研究,并且在opengl/directX上实现了一个效率极高的脏区刷新及渲染引擎。实际上,gl/dx这种图形api,通过修改投影矩阵,我们可以在顶点处理阶段就进行裁剪,将渲染效率大幅度提高。、这部分涉及到gl/dx的渲染流水线以及数学相关知识。在完成本文档后再深入的了解一些比较好玩的内容。

  • 关于控件的布局,包括控件的尺寸和位置计算,是最复杂的一个部分,在我们现在的引擎中,并没有实现具体的布局引擎,关于布局,在完成本文档后再深入的了解布局相关内容。 说实话,布局算法太多了,这个需要深入思考后,具体一一描述了。每个算法背后都是有优缺点。

    7.  UIPLib的入口类CApplication用到的设计模式:单例和模板方法
  • init模板方法,初始化各个子系统

设计模式在UI系统开发中的应用(导读)

初始化模板方法.png

  • 鼠标和键盘事件的分发

  • RunLoop

  • CApplication本身是单例模式,支持游戏模式(独占模式,cpu 100%)和UI模式

UIPControl.lib库(实现两个在后面程序中要用到的控件)

设计模式在UI系统开发中的应用(导读)

内容3.png

  • UIPIconButton 用来显示带Icon的Button,演示了如何增加事件以及渲染

  • UIPaintArea 与Canvas类似,规定了一个显示区,并演示了CRenderEvent事件如何使用

设计模式在UI系统开发中的应用(导读)

paintArea.png

UIPAnimation.exe (以UIPLib/UIPControl为基础,实现一个贝塞尔路径跟随动画演示效果)

设计模式在UI系统开发中的应用(导读)

生成路径.gif

设计模式在UI系统开发中的应用(导读)

贝塞尔曲线路径跟随及方向调整.gif

用到的设计模式:

  • ISprite使用桥接模式实现
    //动画精灵接口,桥接模式
    //桥接模式的核心是接口与实现分离
    //也就是面向接口编程

  • 工厂方法(使用std::shared_ptr防止内存泄露)

设计模式在UI系统开发中的应用(导读)

精灵工厂.png

  • CPathFollower类使用flyWeight模式
设计模式在UI系统开发中的应用(导读)

flyweight.png

  • CAnimationController使用备忘录模式,用于实现Record/Replay功能

UIPPaint.exe (以UIPLib/UIPControl为基础,实现一个简单的绘图程序)

设计模式在UI系统开发中的应用(导读)

UIPaint.png

设计模式在UI系统开发中的应用(导读)

paint.png

  • CDrawerVisitor类使用了Vistor模式,用于渲染辅助功能
  • 使用Command模式实现了Undo/Redo功能,在程序中你可以使用鼠标中键来进行Undo,使用鼠标右键来进行Redo.或者使用ctrl+z进行Undo,ctrl+y进行Redo.
  • ResponsibleChain系统使用职责链模式实现了一个帮助系统,程序中你按F1,会根据当前的控件焦点显示帮助内容
  • 程序中各个图标的切换随之功能切换(例如按圆形就绘制圆圈),使用状态机模式来管理,整个操作就非常清晰明了,特别棒
  • CFacadeMediator类是整个核心结构,即实现了门面模式,又实现了中间者模式,他是大内总管,所有的事情都需要到这个类来中转。
设计模式在UI系统开发中的应用(导读)

状态子系统.png

设计模式在UI系统开发中的应用(导读)

图元子系统.png

设计模式在UI系统开发中的应用(导读)

undo_redo子系统.png

设计模式在UI系统开发中的应用(导读)

事件.png

设计模式在UI系统开发中的应用(导读)

其他.png

设计模式在UI系统开发中的应用(导读)

事件处理.png

具体细节和源码,这几天会全部出来,毕竟都是现成的PPT,我就偷懒直接截图黏贴好了。分如下三篇:

UIPLib篇

UIPControl/UIPAnimation篇

UIPPaint篇

源码在发布完成后上传我的github。本周全部完成。

目前,本人正在记录开发周记,总结近一年服务器和前端开发的经验总结,以及对mozila spidermonkey,google v8, ms chakracore 三大引擎的研究与选择。有兴趣可以关注一下,每天更新。感觉效果蛮好的

周记(2017/3/26-2017/4/2)

周记(2017/4/3-2017/4/9)

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » 设计模式在UI系统开发中的应用(导读)

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址