从〇开始构架前端(NLDV框架)

从〇开始构架前端(NLDV框架)

框架 设计模式



摘要:一个普通应用,大到微信, 小到豆瓣FM,必不可少的都包括四部分:Network、Logic、Data、View(NLDV)。如何把他们组合起来,结构清晰、又协作便利,是前端主程的基本修养。本文用通(有)俗(点)易(啰)懂(嗦)的语言,界定了这四个模块的职能范围,同时提供了一种简单易用的组织方式。知者可互动,不知者可参考。



目录

  • 从〇开始构架前端(NLDV框架)
  • 目录
  • 先唠点嗑
  • 从账号登陆谈起
  • 职责分配
    • Network
    • Logic
    • Data
    • View
  • WHY NLDV?
    • 引擎更换
    • 制作机器人
    • 逻辑清晰
  • 框架之外(下回分解)
  • NLDV的适用场景(下回分解)

先唠点嗑

说说自己吧:毕业三年,经历4个项目,前两个主做功能开发,后两个全面负责。因为大学对UI交互深感兴趣,梦想成为优秀的交互设计师,所以毕业就做了前端,想着至少也离得近点。不料一入代码深似海,以前看过的十几本交互书也随风而去,脑子里剩下的只有:几行干巴巴的代码、几个平台的API、和一点不成熟的总结。借此机会,整理一下。

我把他名为NLDV,也就图一叫着方便(首字母的组合),并不是想标新立异。你或许会想到MVC,其实本质上跟MVC没啥区别。只是与时俱进,现在App几乎都是连着网的,也就把Network提出来了。

从第三个项目开始,这个NLDV的结构在我意识里渐渐清晰。第四个项目(游戏),因为是从零开始,我把NLDV的结构应用到了项目中。经历了渲染引擎更换和网络引擎更换,过程中其它模块儿做得改动极少,切身体会到它的妙处,忍不住前来分享。

从账号登陆谈起

我们从一个最简单的登陆请求谈起。按照NLDV框架的思想,步骤如下:

  1. Logic告诉Network:以后你收到来自远方服务器的消息都跟我打声招呼,不然我告诉程序员整死你丫。(Logic向Network注册网络监听函数。)
  2. 用户点击登陆按钮,此时View调用Logic的登录方法。Logic赶紧写封信,告诉Network把这封信送到服务器。(Logic根据传入的参数,构造相应的消息体,Network负责把消息发出去)
  3. 漫长的等待。。。
  4. Network终于等到服务器发来的消息,就急急忙忙递给Logic。Logic打开信封一看:“尼玛,居然能一次成功了!32个赞!”
    1. 可是信上还有性别,年龄,头像,邮箱等等等信息,头都大了,不记下来恐怕是隔夜就忘啊。于是,找来Logic的御用秘书Data(只有Logic能写入),这些信息就交给你了,临时存储还是永久存储我不管,反正我和View来取的时候,你要能给我。
    2. 好消息要和大家分享,于是Logic全应用广播:“我们已经出色的完成了登陆任务,大家再接再厉”
  5. View收到此广播消息,用界面告诉用户“亲爱的,你登陆成功了”。到此,完成一次登陆。

    PS:对于大多数界面实例,Logic刚刚发的这条广播是可以当耳边风的,因为跟自己业务无关。但,对于登陆界面来说,他必须时刻竖起耳朵监听这个消息,要不然就是失职。所以一般情况下登陆View会在发送登录请求之前就向系统注册监听这个消息的函数,以确保万无一失。这是后话,没看懂也没关系

职责分配

首先,看一幅图:

通过上面的例子和图示,可以来总结一下NLDV四大家族各自的职能范围了:

Network

Network的是数据交流的基础。在这里并不单指socket,并且不暴露任何底层网络的实现。而是一个更加完整、稳定,有纠错功能的职能单位。主要功能:

  • 响应Logic的调用,将构造好的消息体转换成服务器能识别的字节串,发送出去。
  • 接收服务器发过来的字节串,转换成前端可识别的结构体,通知Logic。
    • 前后端在定义消息的时候,一般会用一个消息号(/或 主消息号-子消息号对)来唯一标识一种消息。
    • 而Logic也不止一个,账号系统,业务系统等,每个系统有对应的Logic,分别处理相关的业务逻辑。
    • 一个Logic仅仅会对某一些消息感兴趣,所以,它只向Network注册自己感兴趣的消息号。
  • 容错处理。比如有限次的自动重发,需要的时候自动重连,网络彻底不可用时通知Logic等。

我们用最少的接口来定义它:

  1. // Real msg struct will implement this interface, adding some getter/setters.
  2. interface IMessage
  3. {
  4. uint getMsgId();// unique id for a type of msg
  5. byte[] toBytes();// serialize to bytes.
  6. void parseBytes( byte[] bytes); //deserialize to useful info.
  7. }
  8. //Generally, "Logic" will implement this interface for recieving data
  9. interface INetworkHandler
  10. {
  11. void onMessageRecv( IMessage msg);
  12. }
  13. interface INetwork
  14. {
  15. void send( IMessage msg );
  16. void registHandler( uint msgId, INetworkHandler handler );
  17. void unregistHandler( uint msgId, INetworkHandler handler );
  18. }

Logic

Logic是一个应用中核心实现业务逻辑的部分。主要功能有:

  • 响应来自用户(View)的功能请求。或通过写入Data来改变状态,或构造消息体发送到服务器。
  • 收到网络消息后,做相应的逻辑处理,将数据的改变写入Data,最后广播本地事件。
    • 这里的本地事件通常用一个 字符串或者整数指代,称为本地事件ID。
    • 这个过程通常会用到观察者模式。有一个本地消息中心LocalMessageCenter,监听者(通常是View)用本地事件ID来向LocalMessageCenter注册,而Logic调用LocalMessageCenter.dispatch( localEventId ) 即可广播此本地事件。
    • 是的,Logic直接调用View的方法也能达到同样的目的。但是,为了减小Logic和View之间的耦合性,还是选用LocalMessageCenter作为中间层。随着需求的改变,View类可能面目全非,但LocalMessageCenter的接口却可以长久不变。

Logic的大致结构如下:

  1. class SomeLogic implemets INetworkHandler
  2. {
  3. SomeLogic()
  4. {
  5. Network.getInstance().registHandler(1, this);
  6. Network.getInstance().registHandler(2, this);
  7. }
  8. void onMessageRecv( IMessage msg)
  9. {
  10. switch( msg.getMsgId() )
  11. {
  12. case 1:
  13. logicHandler1(IMessage msg);
  14. break;
  15. case 2:
  16. logicHandler2(IMessage msg);
  17. break;
  18. ...
  19. }
  20. }
  21. //请求操作
  22. void logicReq1(...);
  23. void logicReq2(...);
  24. ...
  25. //消息处理
  26. void logicHandler1(IMessage msg)
  27. {
  28. //TODO: 收到消息,逻辑处理
  29. //TODO: 向Data写入数据
  30. //TODO: 广播本地事件
  31. LocalMessageCenter.getInstance().dispatch( "Logic1Compelete" );
  32. };
  33. void logicHandler2(IMessage msg);
  34. ...
  35. }
  36. ILocalMessageHandler
  37. {
  38. void onLocalMessage( String msg );
  39. }
  40. LocalMessageCenter
  41. {
  42. static LocalMessageCenter getInstance(); // Singleton
  43. void dispatch( String msg );
  44. void regist( String msg, ILocalMessageHandler handler );
  45. void unregist( String msg, ILocalMessageHandler handler );
  46. }

Data

这个模块是全应用的数据中心。提供两个功能:

  • 存储。前面已经提到,基本只有Logic对Data有写入权限。由于没有想到好的办法,这个规范暂时只能通过编码习惯来约定,没有做框架级的约定,如果大家有好的办法,欢迎补充。Logic 不关心数据的存储方式:同步OR异步,临时OR永久;这些都由Data自己决定。
  • 读取。Logic和View都会使用到Data中的数据。但是需要注意异步读取的问题。一般App要求View对操作的响应速度要在0.1s级别。所以,若涉及大量的数据存储或读取,便需要借助异步处理。对于存储,我们可能不是那么关心异步存储什么时候结束,只需要知道它成功了既可。但对于读取,经常遇到的情况是:页面上加个菊花,数据完全读取成功之后,移除菊花。这就需要一个通知机制。此时,我们也会用LocalMessageCenter作为通信的桥梁。

View

NLDV框架对View的限制,相比以上3个模块,非常少。因为,对于NLDV框架来说,View跟特定的平台无关,即它是对各种不同平台显示框架的抽象。在IOS里它是UIFramework,在Android里它是xxx,在游戏里它是openGL,甚至,在下面会讲到的机器人模拟器里它是一堆测试代码。

在这个框架里,View只在两个过程中出现:

  1. 调用Logic的方法,发送逻辑请求。
  2. 监听本地事件,读取Data,显示内容。

只补充一点:在View显示过程中,需要用到很多二级数据(二级数据,就是跟原始数据相对,对原始数据进行整合或者筛选后得到的数据),这些二级数据的处理过程最好在View中处理。因为这些代码大多跟特定的界面有关,而跟App的主要逻辑关系不大,为了以后更改方便,最好写在View里。

WHY NLDV?

看到这里,读者大概能隐约的感受到NLDV的一些优点,但是又不那么清晰,要不要看下去呢?下个里程碑就到了看这个人扯淡有用么?再看下去两盘Dota的时间可就没了丫。。。

别急,举几个栗子提提神。

引擎更换

最早,因为兼容PC版本的斗地主,我们采用了原始的字节对齐的方式进行网络传输。又因为设计失误,网络层字节的pack和unpack以及异步读取的处理,都各种出问题。(因为需要跨平台,所以我们用了C++语言,采用了最基础的BSD socket进行socket连接。)

结果是,游戏在网络不稳定的情况下各种闪退。这下产品经理不高兴了。又因为当初开发网络层的同学接手了其他事情,只剩下我各种修修补补,最终也没能彻底解决问题。

于是,我决定重写网络层。(妈蛋,早看这段代码不爽了)。于是我花了两天封装了一个带自动重连和容错功能,支持异步接受和发送的GameSocket,简单测试可以发送和接受字节。5分钟替换游戏中的旧网络层,你猜,怎么着?一次Run就登陆成功了!点了几下,所有功能完好如初!尼玛,世界上有比这还幸福的事情么?

其实,别听我说的挺牛逼的,其实替换过程就改了不到10行代码。因为实在是跟Logic、Data、View没啥耦合的地方。

制作机器人

一般在线游戏,都会有一两个用户没问题,大量用户就有问题的时候。所以,机器人测试总是必要的。

当我把前端代码交给后端,简单介绍了一下结构之后,后端的小伙伴儿们都惊呆了。不是因为他看到这框架有多么优秀,而是:“这样,我只要写一个while循环,500行代码就能完成一个机器人了啊。我还申请了一个星期来做这个事情呢!”(这是他的原话)。

说的更具体点,制作一个机器人就这么几步:

  1. 把所有的View代码文件删掉。
  2. 写一个AndroidLoop类。在这个类里,监听斗地主主流程里必须处理的LocalMessage,在适当的时候发送主流程中的请求。(对于斗地主来说,主流程包括登陆、选房间、抢地主、出牌、退房间。每个应用有所不同,灵活自便。)
  3. NLD(NLDV去掉V)部分都不变,几乎不用改一行代码。

逻辑清晰

框架的作用,理论层面上规范了整个软件的结构;而在实现层面,通俗一点,它就规范了什么代码该写在哪里,不要随地乱放

作为一个针对性很强的框架,在上述过程中,NLDV约束了很多可能不需要约束的规范。其中大部分是项目中的干货经验。我知道他并不总是好的,我考略了很久要不要把他们加进来。最终,我还是写下来了,考虑到刚开始从零开始写应用的读者来说,这些可能避免他们走很多弯路;而对有经验的读者来说,可能他们有判断的能力,可以取舍自如。

我想,如果严格按照NLDV框架来编写程序,显而易见的好处就是:

  1. 层次清晰,出现问题容易定位。
  2. 主程再也不用担心同事们把代码写得到处都是了。。。

框架之外(下回分解)

NLDV的适用场景(下回分解)

因为各种原因,这篇博客断断续续写了两个星期了,再不发布就要胎死腹中了。所以,最后两节放在这篇日志的续集中写。如果您感兴趣,请私信我,我会尽快补上。

时间: 2024-08-04 15:59:16

从〇开始构架前端(NLDV框架)的相关文章

最轻量级的前端Mvc框架backbone

最轻量级的前端Mvc框架backbone依赖最轻量级的库understore backbone并非将前端再次切分为mvc,而是分为了七大模块,分别是:Events.Model.Collection.Router.History.Sync.View 一个Model对应一个View,如果是多个Model时,则进化为一个Collection对应一个View Sync负责与服务器端进行交互 官方网站 http://backbonejs.org/ github地址 https://github.com/j

web前端ui框架好用的有哪几个

如今移动端网站越来越火热,移动端的网站也纷纷崛地而起,在进行web前端开发(http://www.maiziedu.com/course/web/)时,需要用到适合自己项目的框架就需要有偶遇的机会,特别是适合移动端的web前端框架,很难遇得到,下面小编就推荐几款合适的移动web 前端ui框架给大家,能大大提升我们的开发效率. Amaze UI Amaze UI是一个轻量级(所有CSS和JS gzip后100kB左右).Mobile first的前端框架, 基于开源社区流行前端框架编写. Froz

960网格布局框架(前端css框架)的使用方法

960框架总宽960px CSS框架已经出现很长时间了,关于这些框架的用处也被我们讨论了很多遍了.有人说,CSS框架不够先进,还有人说这些框架大大的节省了他们的开发时间.在此,我们将不再讨论这个问题. 前段时间,我了解到了CSS框架.经过对Malo.BluePrint和960做了实验对比后,我得出一个结论:我最喜欢960CSS框架. 本教程将解释这个框架的基本原理,这样你就可以用960来快速进入开发. 基本原理 你必须知道一些基本原理来“学习这个框架是如何工作的”.你可以通过实验(或者是用fir

前端常用框架知识点收集

前端组件库 搭建web app常用的样式/组件等收集列表(移动优先) 0. 前端自动化(Workflow) 前端构建工具 Yeoman – a set of tools for automating development workflow gulp – The streaming build system grunt – the JavaScript Task Runner F.I.S – 前端集成解决方案 前端模块管理器 Bower – A package manager for the w

前端Js框架汇总

一.前端框架库: 1.Zepto.js 地址:http://www.css88.com/doc/zeptojs/ 描述:Zepto是一个轻量级的针对现代高级浏览器的JavaScript库, 它与jquery有着类似的api. 如果你会用jquery,那么你也会用zepto.关于Zepto认知我也是通过与一位腾讯朋友聊天的时候知道的,只作了些基础的了解. 2.SUI Mobile 地址:http://m.sui.taobao.org 描述:SUI Mobile 是一套基于 Framework7 开

js架构设计模式——前端MVVM框架设计及实现(一)

前端MVVM框架设计及实现(一) 最近抽出点时间想弄个dom模块化的模板引擎,不过现在这种都是MVVM自带的,索性就想自己造轮子写一个简单的MVVM框架了 借鉴的自然还是从正美的avalon开始了,我记得还是去年6月写过一个系列的avalon源码分析的,不过那时候0.7版本,不够健全,现在已经好太多了 框架是面向一个领域,提供一套解决方案,那么我们用前端的MVVM能为我们带来什么便利? 关注点分离 操作数据即操作DOM 动态模板 关注点分离是MVVM与身俱来的,操作数据即操作DOM,是VM中的访

【转载】目前最受欢迎的WEB前端UI框架

目前WEB前端UI框架受到新人追捧,下边为大家列出目前最受欢迎.最优秀的前端框架以供大家选择一款适合自己的! Bootstrap 目前开源社区最受欢迎的项目之一,可谓大名鼎鼎了,最新版本3.x兼容IE9+ 官网:http://getbootstrap.com/ Foundation 属于WEB前端框架的先驱者,知名度被Bootstrap反超,但其优秀程度相比Bootstrap只强不弱!最新版本5.x兼容IE9+ 官网:http://foundation.zurb.com/ Semantic UI

web前端技术框架选型参考

一.出发点 随着Web技术的不断发展,前端架构框架.UI框架.构建工具.CSS预处理等层出不穷,各有千秋.太多的框架在形成初期,都曾在web领域 掀起过一场技术浪潮,可有些却仅仅是昙花一现,随着他们用户量的逐渐减少,社区也越来越不活跃.如:meteor.backbone.ember.knockout. 不禁感叹技术的更新换代来的太突然.为了追赶技术更新的脚步,保证技术实施的高性能,强兼容性,并且不会再短时间内被时代所遗弃.以下为目 前常见的主流技术参考,根据github关注度排名: 架构框架 框

了解前端的框架知识

构建工具(自动) Grunt.js:生态强大,发展速度快,有大量可选插件: Gulp.js:流式项目构建工具: Browserify.js:Node.js模块,主要用于改写现有的CommonJS模块,使得浏览器端也可以使用这些模块: Uglify.js:JavaScript解析器.压缩工具和代码美化库. 软件包管理工具 Homebrew (Mac OS):Apple Mac OS下的软件安装工具: Apt:Debian.Ubuntu等系列Linux系统的软件包管理工具,可用来安装.删除.升级软件