许式伟的架构课
许式伟
七牛云CEO
立即订阅
20090 人已学习
课程目录
已更新 72 讲 / 共 77 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 怎样成长为优秀的软件架构师?
免费
基础平台篇 (21讲)
01 | 架构设计的宏观视角
02 | 大厦基石:无生有,有生万物
03 | 汇编:编程语言的诞生
04 | 编程语言的进化
05 | 思考题解读:如何实现可自我迭代的计算机?
06 | 操作系统进场
07 | 软件运行机制及内存管理
08 | 操作系统内核与编程接口
09 | 外存管理与文件系统
10 | 输入和输出设备:交互的演进
11 | 多任务:进程、线程与协程
12 | 进程内协同:同步、互斥与通讯
13 | 进程间的同步互斥、资源共享与通讯
14 | IP 网络:连接世界的桥梁
15 | 可编程的互联网世界
16 | 安全管理:数字世界的守护
17 | 架构:需求分析 (上)
18 | 架构:需求分析 (下) · 实战案例
19 | 基础平台篇:回顾与总结
加餐 | 我看Facebook发币(上):区块链、比特币与Libra币
加餐 | 我看Facebook发币(下):深入浅出理解 Libra 币
桌面开发篇 (16讲)
20 | 桌面开发的宏观视角
21 | 图形界面程序的框架
22 | 桌面程序的架构建议
23 | Web开发:浏览器、小程序与PWA
24 | 跨平台与 Web 开发的建议
25 | 桌面开发的未来
26 | 实战(一):怎么设计一个“画图”程序?
27 | 实战(二):怎么设计一个“画图”程序?
28 | 实战(三):怎么设计一个“画图”程序?
29 | 实战(四):怎么设计一个“画图”程序?
30 | 实战(五):怎么设计一个“画图”程序?
31 | 辅助界面元素的架构设计
课外阅读 | 从《孙子兵法》看底层的自然法则
加餐 | 想当架构师,我需要成为“全才”吗?
32 | 架构:系统的概要设计
33 | 桌面开发篇:回顾与总结
服务端开发篇 (14讲)
34 | 服务端开发的宏观视角
35 | 流量调度与负载均衡
36 | 业务状态与存储中间件
37 | 键值存储与数据库
38 | 文件系统与对象存储
39 | 存储与缓存
40 | 服务端的业务架构建议
41 | 实战(一):“画图”程序后端实战
42 | 实战(二):“画图”程序后端实战
43 | 实战(三):“画图”程序后端实战
44 | 实战(四):“画图”程序后端实战
45 | 架构:怎么做详细设计?
46 | 服务端开发篇:回顾与总结
加餐 | 如何做HTTP服务的测试?
服务治理篇 (11讲)
47 | 服务治理的宏观视角
48 | 事务与工程:什么是工程师思维?
49 | 发布、升级与版本管理
50 | 日志、监控与报警
加餐 | 怎么保障发布的效率与质量?
51 | 故障域与故障预案
52 | 故障排查与根因分析
53 | 过载保护与容量规划
54 | 业务的可支持性与持续运营
55 | 云计算、容器革命与服务端的未来
56 | 服务治理篇:回顾与总结
架构思维篇 (9讲)
57 | 心性:架构师的修炼之道
用户故事 | 站在更高的视角看架构
58 | 如何判断架构设计的优劣?
59 | 少谈点框架,多谈点业务
60 | 架构分解:边界,不断重新审视边界
加餐 | 实战:“画图程序” 的整体架构
61 | 全局性功能的架构设计
62 | 重新认识开闭原则 (OCP)
63 | 接口设计的准则
许式伟的架构课
登录|注册

26 | 实战(一):怎么设计一个“画图”程序?

许式伟 2019-07-19
你好,我是七牛云许式伟。
到上一讲为止,桌面程序架构设计的基本结构就讲完了。直到现在为止,我们没有讨论任何与具体的应用业务逻辑本身相关的内容。这是因为探讨的内容是普适有效的设计理念,整个讨论会显得很抽象。
今天我们结合一个实际的应用案例,来回顾一下前面我们介绍的内容。
我们选择了做一个 “画图” 程序。选它主要的原因是画图程序比较常见,需求上不需要花费过多的时间来陈述。
我们前面说过,一个 B/S 结构的 Web 程序,基本上分下面几块内容。
Model 层:一个多用户(Multi-User)的 Model 层,和单租户的 Session-based Model。从服务端来说,Session-based Model 是一个很简单的转译层。但是从浏览器端来说,Session-based Model 是一个完整的单租户 DOM 模型。
View 层:实际是 ViewModel 层,真正的 View 层被浏览器实现了。ViewModel 只有 View 层的数据和可被委托的事件。
Controller 层:由多个相互解耦的 Controller 构成。切记不要让 Controller 之间相互知道对方,更不要让 View 知道某个具体的 Controller 存在。
画图程序的源代码可以在 Github 上下载,地址如下:
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《许式伟的架构课》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(25)

  • 田常发
    许老师,我想问一下,学go的话要不要去学一下,设计模式,有的话,您有没有什么资料可以推荐一下?

    作者回复: 学什么语言都要设计模式。不过设计最重要的不是模式,而是关于解耦的思考

    2019-07-23
    12
  • xiaobang
    这一章看的有点卡,主要是因为对前端知识不熟悉。我看到js代码里面出现class关键字一度怀疑用的是什么语言。另外提一个建议,老师讲的时候能不能按照软件设计的过程来展开。比如开始做需求分析,这个画图程序要提供哪些功能,支持哪些图形等。然后列出平台对画图的支持,再描述在平台上直接硬写会写成什么样的程序,最后按mvc模式重构。我感觉这样能更好的表现设计的思路。

    作者回复: 多谢建议

    2019-07-24
    8
  • Linuxer
    由Controller来创建具体Shape这样会不会,model和controller又耦合了呢

    作者回复: controller本来就会耦合model和view。重点是controller之间不要耦合

    2019-07-19
    6
  • Smallfly
    五讲画图程序已经讲完了,第一次只是泛泛而读,这次打算精读,并整理一下自己的理解。

    第一讲的重点架构思想包括:

     1. 为了避免 Model 知道 View 的实现细节,可以让 Model 耦合 GDI 接口。模块间通信如果避免不了耦合,就耦合稳定的模块,这个模块最好是系统的,因为系统模块相对于业务模块通常更加稳定;

     2. ViewModel 持有 Model,并由 Controller 来更新 Model/ViewModel;

     3. ViewModel 定义 Controller 的行为规则,但并不关心 Controller 的具体行为。Controller 可以选择性的接管 ViewModel 的事件;

     4. ViewModel 协调 Model 和 Controller,启到承上启下的作用,所以 ViewModel 职责的划分对程序的结构有比较大的影响;

     5. Model 的结构稳定,容易做到平台无关,ViewModel 会跟平台强关联;

     6. 避免 Controller 之间的耦合,可以使用 ViewModel 作为通信中介者;

     7. 相同的 Model 可能在 Controller 层有不同的展现方法;

    本讲中 View 应该理解为 ViewModel,View 是不应该持有 Model 数据的,文中老师也说了网页的 View 是由浏览器实现的,个人觉得从严格意义上将,这不算是 MVC 模式,也不像 MVVM,应该叫 MVMC?

    下载源码并切换到 v26 分支,用浏览器打开 index.html 文件,可使用开发者工具进行断点调试。

    作者回复: 👍

    2019-08-17
    3
  • Smallfly
    下载源码并切换到 v26 分支,用浏览器打开 index.html 文件,可使用开发者工具进行断点调试。

    绘制矩形的过程:

     1. 点击 `Creat Rect` 按钮,激活 react.js(Controller);
     2. view.js(View) 接收到 drawing 的 onmousedown 事件,传递给事件的实现者 react.js;
     3. react.js 接收到 onmousedown 事件,记录起始点 p1;
     4. 同理,react.js 接收到 onmousemove 事件,记录 p2, 并调用全局函数 invalidate 绘制;
     5. invalidate 交给 qview.invalidateRect 处理(为什么不直接调用 qview.invalidateRect?);
     6. qview.invalidateRect 调用 qview.onpaint,在 onpaint 中调用当前激活的 rect.js 的 onpaint 方法;
     7. rect.js 中 onpaint 调用 buildShape() 创建 QRect(Model) 实例,然后调用该实例的 onpaint 方法绘制;
     8. 绘制结束时 react.js 接收到 onmouseup 事件,把当前 model 实例存入 doc(Model),保证重绘时能够再次绘制原来的图形;

    MVC 角色的通信过程:

    V -> C -> V -> C -> M

    作者回复: react.js => rect.js

    2019-08-17
    3
  • 八哥
    CEO,js写的还这么好。厉害
    2019-07-19
    3
  • Geek_88604f
    看了几遍捋一下思路:view接收到用户事件,把事件处理委托给controller,由controller来操作model。是这样的吗,老师?

    作者回复: 是的

    2019-08-06
    2
  • kyle
    掉队了
    2019-07-19
    2
  • Geek_88604f
    view.js中"let ctx = this.drawing.getContext("2d")",这段代码是什么意思?

    作者回复: 取得二维(2D)的 Canvas 上下文,用于绘制。详细参阅: https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement/getContext

    2019-08-04
    1
  • Luke
    保持跟进,目前只能说好像有点懂了,还是得在自己项目上多思考下,不是真的懂了
    2019-07-19
    1
  • Aaron Cheung
    大前端 还是非常有价值 打卡
    2019-07-19
    1
  • Lukia
    许老师好,文中有很多地方都用Selection概念用来做类比。那么具体应该怎么去理解Selection这个概念呢?

    作者回复: selection 最直白的理解是被选中的对象。

    2019-09-18
  • Halohoop
    划重点:“依赖选择是考虑耦合的一个关键因素。在依赖选择上,我们会更倾向于依赖接口更为稳定的组件,因为这意味着我们的接口也更稳定。”
    2019-08-16
  • Tesla
    老师好,请问一下Controller之间不要知道彼此的意思,是不要知道彼此实现的细节吗?有很多时候,我会在一个controller方法里调用另一个方法,将功能组合再传到客户端,这样的做法好不好呢?

    作者回复: 能够举一个实际的例子吗

    2019-08-12
    1
  • Geek_88604f
    浏览器打开index.htm,首先创建canvas画布对象,后面的画图操作都是在画布对象上进行的。
            接着加载dom对象,注意这里并没有实例化dom对象。
            然后加载view对象,并且实例化view对象和dom对象。view对象中定义了事件处理规则,接管画布的事件处理,将onpaint委托给了doc和contraller,注意doc的onpaint和contraller的onpaint绘制的是不同的内容,还有就是定义了contraller的操作规则。
            接下来就是加载contraller,调用view的方法注册自己,并将事件处理委托给contraller。
            最后加载和显示菜单,定义contraller的鼠标点击事件,在点击事件中指定当前contraller。这样当鼠标在画布上移动时,通过层层委托(画布——view——contraller)最终触发contraller的invalidate,invalidate触发onpaint,onpaint触发doc.onpaint。

    作者回复: 👍

    2019-08-10
  • halweg
    华龙点睛
    2019-08-07
  • humor
    为什么controller层和model层都有onpaint方法,这样controller层的onpaint方法不就多余了么

    作者回复: 不一样,画的东西是不同的东西。你可以注释掉这块的onpaint代码看下。

    2019-08-07
  • Geek_88604f
    不太明白是谁来触发invalidateRect的?

    作者回复: controller

    2019-08-05
  • Jian
    最大的收获还是解耦。首先将应用程序进行抽象/分层,然后通过中间的view层将model层和controller层串联在一起。
    controller的使用,就像java中的interface,其有多重实现方式。
    这是第二次读这篇文章了,因为没有接触过前端,不知道前端的实习方式。后面看懂了代码,但是如果能有个流程图样的粗略解释可能会更有利于理解吧。

    作者回复: 多谢建议

    2019-08-01
  • lu
    图形拖动或点击的时候,外面的虚线矩形框绘制是在哪里实现的?

    作者回复: 这个在27讲

    2019-07-26
    1
收起评论
25
返回
顶部