`
lc0451
  • 浏览: 47198 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类

高级基础——转载

阅读更多

1. 在重要的过程上设置拦截接口

如果你要写个远程调用框架,那远程调用的过程应该有一个统一的拦截接口,
如果你要写一个ORM框架,那至少SQL的执行过程,Mapping过程要有拦截接口,
如果你要写一个Web框架,那请求的执行过程应该要有拦截接口,
等等,没有哪个公用的框架可以Cover住所有需求,允许外置行为,是框架的基本扩展方式,
这样,如果有人想在远程调用前,验证下令牌,验证下黑白名单,统计下日志,
如果有人想在SQL执行前加下分页包装,做下数据权限控制,统计下SQL执行时间,
如果有人想在请求执行前检查下角色,包装下输入输出流,统计下请求量,
等等,就可以自行完成,而不用侵入框架内部,
拦截接口,通常是把过程本身用一个对象封装起来,传给拦截器链,
比如:远程调用主过程为invoke(),那拦截器接口通常为invoke(Invocation),
Invocation对象封装了本来要执行过程的上下文,并且Invocation里有一个invoke()方法,
由拦截器决定什么时候执行,同时,Invocation也代表拦截器行为本身,
这样上一拦截器的Invocation其实是包装的下一拦截器的过程,
直到最后一个拦截器的Invocation是包装的最终的invoke()过程,
同理,SQL主过程为execute(),那拦截器接口通常为execute(Execution),原理一样,
当然,实现方式可以任意,上面只是举例。

2. 重要的状态的变更发送事件并留出监听接口

这里先要讲一个事件和上面拦截器的区别,拦截器是干预过程的,它是过程的一部分,是基于过程行为的,
而事件是基于状态数据的,任何行为改变的相同状态,对事件应该是一致的,
事件通常是事后通知,是一个Callback接口,方法名通常是过去式的,比如onChanged(),
比如远程调用框架,当网络断开或连上应该发出一个事件,当出现错误也可以考虑发出一个事件,
这样外围应用就有可能观察到框架内部的变化,做相应适应。

3. 服务域/实体域/会话域分离

任何框架或组件,总会有核心领域模型,比如:
Spring的Bean,Struts的Action,Dubbo的Service,Napoli的Queue等等
这个核心领域模型及其组成部分称为实体域,它代表着我们要操作的目标本身,
实体域通常是线程安全的,不管是通过不变类,同步状态,或复制的方式,
服务域也就是行为域,它是组件的功能集,同时也负责实体域和会话域的生命周期管理,
比如Spring的ApplicationContext,Dubbo的ServiceManager等,
服务域的对象通常会比较重,而且是线程安全的,并以单一实例服务于所有调用,
什么是会话?就是一次交互过程,
会话中重要的概念是上下文,什么是上下文?
比如我们说:“老地方见”,这里的“老地方”就是上下文信息,
为什么说“老地方”对方会知道,因为我们前面定义了“老地方”的具体内容,
所以说,上下文通常持有交互过程中的状态变量等,
会话对象通常较轻,每次请求都重新创建实例,请求结束后销毁。
简而言之:
把元信息交由实体域持有,
把一次请求中的临时状态由会话域持有,
由服务域贯穿整个过程。

4. API与SPI分离

框架或组件通常有两类客户,一个是使用者,一个是扩展者,
API(Application Programming Interface)是给使用者用的,
而SPI(Service Provide Interface)是给扩展者用的,
在设计时,尽量把它们隔离开,而不要混在一起,
也就是说,使用者是看不到扩展者写的实现的,
比如:一个Web框架,它有一个API接口叫Action,
里面有个execute()方法,是给使用者用来写业务逻辑的,
然后,Web框架有一个SPI接口给扩展者控制输出方式,
比如用velocity模板输出还是用json输出等,
如果这个Web框架使用一个都继承Action的VelocityAction和一个JsonAction做为扩展方式,
要用velocity模板输出的就继承VelocityAction,要用json输出的就继承JsonAction,
这就是API和SPI没有分离的反面例子,SPI接口混在了API接口中,
合理的方式是,有一个单独的Renderer接口,有VelocityRenderer和JsonRenderer实现,
Web框架将Action的输出转交给Renderer接口做渲染输出。

5. 扩展接口职责尽可能单一,具有可组合性

比如,远程调用框架它的协议是可以替换的,
如果只提供一个总的扩展接口,当然可以做到切换协议,
但协议支持是可以细分为底层通讯,序列化,动态代理方式等等,
如果将接口拆细,正交分解,会更便于扩展者复用已有逻辑,而只是替换某部分实现策略,
当然这个分解的粒度需要把握好。

6. 微核插件式,平等对待第三方

大凡发展的比较好的框架,都遵守微核的理念,
Eclipse的微核是OSGi, Spring的微核是BeanFactory,Maven的微核是Plexus,
通常核心是不应该带有功能性的,而是一个生命周期和集成容器,
这样各功能可以通过相同的方式交互及扩展,并且任何功能都可以被替换,
如果做不到微核,至少要平等对待第三方,
即原作者能实现的功能,扩展者应该可以通过扩展的方式全部做到,
原作者要把自己也当作扩展者,这样才能保证框架的可持续性及由内向外的稳定性。

7. 不要控制外部对象的生命周期

比如上面说的Action使用接口和Renderer扩展接口,
框架如果让使用者或扩展者把Action或Renderer实现类的类名或类元信息报上来,
然后在内部通过反射newInstance()创建一个实例,
这样框架就控制了Action或Renderer实现类的生命周期,
Action或Renderer的生老病死,框架都自己做了,外部扩展或集成都无能为力,
好的办法是让使用者或扩展者把Action或Renderer实现类的实例报上来,
框架只是使用这些实例,这些对象是怎么创建的,怎么销毁的,都和框架无关,
框架最多提供工具类辅助管理,而不是绝对控制。

8. 可配置一定可编程,并保持友好的CoC约定

因为使用环境的不确定因素很多,框架总会有一些配置,
一般都会到classpath直扫某个指定名称的配置,或者启动时允许指定配置路径,
做为一个通用框架,应该做到凡是能配置文件做的一定要能通过编程方式进行,
否则当使用者需要将你的框架与另一个框架集成时就会带来很多不必要的麻烦,
另外,尽可能做一个标准约定,如果用户按某种约定做事时,就不需要该配置项。
比如:配置模板位置,你可以约定,如果放在templates目录下就不用配了,
如果你想换个目录,就配置下。

9. 区分命令与查询,明确前置条件与后置条件

这个是契约式设计的一部分,尽量遵守有返回值的方法是查询方法,void返回的方法是命令,
查询方法通常是幂等性的,无副作用的,也就是不改变任何状态,调n次结果都是一样的,
比如get某个属性值,或查询一条数据库记录,
命令是指有副作用的,也就是会修改状态,比如set某个值,或update某条数据库记录,
如果你的方法即做了修改状态的操作,又做了查询返回,如果可能,将其拆成写读分离的两个方法,
比如:User deleteUser(id),删除用户并返回被删除的用户,考虑改为getUser()和void的deleteUser()。
另外,每个方法都尽量前置断言传入参数的合法性,后置断言返回结果的合法性,并文档化。

分享到:
评论

相关推荐

    c++ 学习经典教材 ————易学C++

    C++不仅在软件开发领域广泛使用,也是许多数据结构、编译原理等高级课程的基础。 - **描述**:通过重复“非常好的书籍”,该描述突出了这本书在C++学习中的价值,暗示它能够提供易于理解和实践的C++知识。 ### 2. ...

    Java核心技术 原书第9版 (卷1 基础知识) + (卷2 高级特性).pdf ,2本,带超详细书签目录

    Java核心技术 原书第9版 (卷1 基础知识) + (卷2 高级特性).pdf ,2本,带超详细书签目录 ——这是特别好的一个资源,强烈推荐!!! 本资源转载自网络,供学习研究之用,如用于商业用途,请购买正版,如有侵权,请...

    项目综合案例采用两年所学的内容

    ———————————————— 版权声明:本文为CSDN博主「@Live@And@Learn@#」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:...

    TCR FC型SVC的研究及MATLAB仿真——一种电力节能设备.pdf

    在给定的文件《TCR FC型SVC的研究及MATLAB仿真——一种电力节能设备.pdf》中,作者许双宏介绍了TCR FC型静止无功补偿器(Static Var Compensator, SVC)的设计和仿真。本文将详细解析文档中提及的关键技术和知识点。...

    GT-Grid 1.0 基础教程(一)转载

    ### GT-Grid 1.0 基础教程(一)——纯客户端只读列表开发详解 #### 一、教程背景与目标 本教程旨在帮助初学者快速掌握如何使用GT-Grid开发纯客户端只读列表的基本技能。对于那些对Ajax技术下的列表组件不太熟悉的...

    【RPA之家转载AA视频教程】32.IF, Elseif -.rar

    在RPA之家平台,我们有幸转载了AA(Automation Anywhere)的高级视频教程,旨在帮助学习者更好地理解和运用RPA技术。AA作为全球领先的RPA供应商,其提供的工具A2019拥有强大的功能和易用性,其中的IF、Elseif和Else...

    从事计算机的人必读(不仅对只是还是对人生都大大有益,过来的高手所写,我只是转载)

    本文将基于标题和描述中的内容,介绍两本经典书籍——《Windows程序设计(第5版)》和《Windows核心编程》,以及它们在Windows编程学习路径中的作用。 首先,由Charles Petzold编著的《Windows程序设计(第5版)》...

    GPU深度发掘(一)GPGPU数学基础教程

    这些概念和技术构成了GPGPU编程的基础,对于进一步探索更高级的并行计算应用至关重要。 #### 6. 相关知识 - **对比Windows和Linux, ATI和NVIDIA**:讨论不同平台和显卡品牌之间的差异。 - **问题**:列出常见问题...

    sql精华笔记(转载)

    在执行一系列可能修改数据库的操作之前调用此命令,可以确保这些操作作为一个整体来对待——要么全部成功,要么全部失败。这对于保证数据一致性至关重要。 **语法示例**: ```sql BEGIN TRANSACTION [transaction_...

    ArcGIS Engine + C# 实例开发教程.pdf

    - 使用MapControl、PageLayoutControl、ToolbarControl和TOCControl创建基础GIS应用框架。 - 创建新项目,设置窗体属性,添加MenuStrip、StatusStrip、SplitContainer、TabControl等控件。 - 设置控件的Dock属性...

    Computational.Complexity.A.Modern.Approach

    本书从计算复杂度的基础概念出发,逐步深入到高级主题,涵盖了以下核心内容: 1. **图灵机与基本的时间和空间复杂度类**:首先介绍了计算模型——图灵机,并定义了时间和空间复杂度的基本类,如P(多项式时间)、NP...

    亚开行-尼泊尔的土地统筹:从计划中的城市“岛屿”到城市转型(英文)-2020.8-62页2020精品报告.pdf

    这份题为《亚开行-尼泊尔的土地统筹:从计划中的城市“岛屿”到城市转型》的报告,是由亚开行(亚洲开发银行)发布,旨在探讨尼泊尔城市规划中土地统筹的新模式——“land pooling”或土地整合,并分析其在城市化...

    LinuxFromScratchv6.2中文版(合译).docx

    手册的发布遵循GNU通用公共许可证(GPL)的精神,允许任何人自由使用、分发和转载,但必须保留原作者及译者的署名,不得对文档进行任何形式的修改或添加额外条件。这种开放分享的态度体现了开源社区的核心价值之一...

    SGDB说明书

    从基础到高级操作,再到维护和故障排查,《SGDB说明书》提供了全面的目录,涵盖了AC伺服系统的所有重要方面,包括: - **基础概念与原理** - **安全指导** - **安装与布线** - **试运行步骤** - **高级配置** - **...

    Learning Node.js Development

    - **内容结构**:本书围绕最新的Node.js版本(9.x.x)展开,覆盖了从基础到高级的所有核心概念和技术细节。 通过本指南的学习,读者将能够熟练掌握Node.js开发的核心技能,并具备构建、测试和部署真实世界应用的...

    c99 学习笔记

    C语言的编程基础涉及数据类型、控制结构、函数、指针等核心概念,而高级编程则涵盖更复杂的话题,如动态内存管理、文件操作、多线程和进程间通信。 内容部分由于OCR扫描结果存在文字识别错误和遗漏,导致部分信息...

Global site tag (gtag.js) - Google Analytics