加入桥接模式
n面临的问题
按照功能要求,配置数据的来源是多方面,比如:xml、properties、txt、DB等等,这也就意味着需要有不同的获取数据的实现来对应这些不同的数据来源。
另外一个方面,对于模块外部的应用而言,他们不关心配置数据是如何来的,他们只关心需要使用的数据,而且在某些需要的情况下,他们可能会要求更多的、不同的数据,他们会认为“只要他们要数据,配置管理模块就应该提供这些数据”。换句话说,这些数据的多少、数据的组合结构是可能发生变化的。
这就出现了两个纬度的变化,一个是获取配置数据这边需要不断扩展,另一个是配置数据所构成的数据模型这边也需要变化和扩展,怎么办呢?
n用桥接模式来解决
n桥接模式基础回顾
初识桥接模式
n定义
将抽象部分与它的实现部分分离,使它们都可以独立地变化。
n结构和说明
桥接模式的知识要点
n桥接模式的知识要点
1:桥接是在被分离了的抽象部分和实现部分之间来搭桥,桥接在程序上就体现成了在抽象部分拥有实现部分的接口对象,维护桥接就是维护这个关系
2:桥接模式的意图:使得抽象和实现可以独立变化,都可以分别扩充。
3:桥接模式可以实现运行时动态组合具体的真实实现,从而达到动态变换功能的目的
4:桥接模式适应于两个纬度的变化,而继承适用于一个纬度的变化
5:使用桥接模式的时候,要注意谁来创建Implementor的对象,并把它设置到抽象部分的对象里面去。
6:从某个角度来讲,桥接模式就是对“面向抽象编程”这个设计原则的扩展。
7:桥接模式是可以连续组合使用的,一个桥接模式的实现部分,可以作为下一个桥接模式的抽象部分
思考桥接模式
n桥接模式的本质是:分离抽象和实现
n何时选用桥接模式
1:如果你不希望在抽象和实现部分采用固定的绑定关系,可以采用桥接模式,来把抽象和实现部分分开,然后在程序运行期间来动态的设置抽象部分需要用到的具体的实现,还可以动态切换具体的实现
2:如果出现抽象部分和实现部分都应该可以扩展的情况,可以采用桥接模式,让抽象部分和实现部分可以独立的变化,从而可以灵活的进行单独扩展,而不是搅在一起,扩展一边会影响到另一边 。
3:如果希望实现部分的修改,不会对客户产生影响,可以采用桥接模式,客户是面向抽象的接口在运行,实现部分的修改,可以独立于抽象部分,也就不会对客户产生影响了,也可以说对客户是透明的
4:如果采用继承的实现方案,会导致产生很多子类,对于这种情况,可以考虑采用桥接模式,分析功能变化的原因,看看是否能分离成不同的纬度,然后通过桥接模式来分离它们,从而减少子类的数目
应用桥接模式
n使用桥接模式来解决问题的思路
可以把获取配置数据这边,设计成为桥接模式的实现部分,而数据模型这边设计成为桥接模式的抽象部分,而且数据模型这边确实需要使用具体实现部分来获取数据,简直就是标准的桥接模式的应用。
而ConfManager就相当于桥接的抽象部分的顶层实现,而GenConfEbo就相当于使用基本的抽象部分的扩展部分,只不过这里采用的是对象组合的方式,而不是标准桥接模式中的对象继承的方式。
具体实现那边,需要先定义出实现的接口来,然后不同的配置方式对应不同的实现。
此时配置管理模块的结构示意如图
加入解释器模式
n面临的问题
自己解析xml,本来也没有什么特别困难的,但是问题就在于,如果xml文件的格式发生了变化,那么读取配置文件的程序就需要做出相应的变更,严重的时候,几乎相当于完全重写程序。
那么怎么解决当xml的结构发生改变过后,能够很方便的获取相应元素、或者是属性的值,而不用再去修改解析xml的程序呢?
n
n用解释器模式来解决
n解释器模式基础回顾
初识解释器模式
n定义
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
n结构和说明
解释器模式的知识要点
n解释器模式的知识要点
1:解释器模式使用解释器对象来表示和处理相应的语法规则,一般一个解释器处理一条语法规则。
2:解释器模式没有定义谁来构建抽象语法树,把这个工作交给了客户端处理
3:使用解释器模式的时候,应该先定义好相应的语法规则,并根据规则制定解释器的语法树;然后客户端在调用解释器进行解释操作的时候,需要自行构建符合语法规则要求的语法树;而解释器模式只是负责解释并执行。
4:从实质上看,解释器模式的思路仍然是分离、封装、简化,跟很多模式是一样的。
思考解释器模式
n解释器模式的本质
解释器模式的本质是:分离实现,解释执行
n
n何时选用解释器模式
1:当有一个语言需要解释执行,并且可以将该语言中的句子表示为一个抽象语法树的时候,可以考虑使用解释器模式。
在使用解释器模式的时候,还有两个特点需要考虑,一个是语法相对应该比较简单,太复杂的语法不合适使用解释器模式;另一个是效率要求不是很高,对效率要求很高的情况下,不适合使用解释器模式。
应用解释器模式
n使用解释器模式来解决问题的思路
要解决通用解析xml的问题,第一步:需要先设计一个简单的表达式语言,在客户端调用解析程序的时候,传入用这个表达式语言描述的一个表达式,然后把这个表达式通过解析器的解析,形成一个抽象的语法树。
第二步:解析完成后,自动调用解释器来解释抽象语法树,并执行每个节点所对应的功能,从而完成通用的xml解析。
这样一来,每次当xml结构发生了更改,也就是在客户端调用的时候,传入不同的表达式即可,整个解析xml过程的代码都不需要再修改了。
n约定简单的语法规则如下,为了通用,用root表示根元素,a、b、c、d等来代表元素,一个简单的xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<root id="rootId">
<a>
<b>
<c name="testC">12345</c>
<d id="1">d1</d>
<d id="2">d2</d>
<d id="3">d3</d>
<d id="4">d4</d>
</b>
<e id="e1">
<f>f1</f>
</e>
<e id="e2">
<f>f2</f>
</e>
</a>
</root>
n约定简单的语法规则如下:
1:获取单个元素的值:从根元素开始,一直到想要获取值的元素,元素中间用“/”分隔,根元素前不加“/”。比如表达式“root/a/b/c”就表示获取根元素下、a元素下、b元素下的c元素的值
2:获取单个元素的属性的值:要获取值的属性一定是表达式的最后一个元素的属性,在最后一个元素后面添加“.”然后再加上属性的名称。比如表达式“root/a/b/c.name”就表示获取根元素下、a元素下、b元素下、c元素的name属性的值
3:获取相同元素名称的值,当然是多个:要获取值的元素一定是表达式的最后一个元素,在最后一个元素后面添加“$”。比如表达式“root/a/b/d$”就表示获取根元素下、a元素下、b元素下的多个d元素的值的集合
4:获取相同元素名称的属性的值,当然也是多个:要获取属性值的元素一定是表达式的最后一个元素,在最后一个元素后面添加“$”,然后在后面添加“.”然后再加上属性的名称,在属性名称后面也添加“$”。比如表达式“root/a/b/d$.id$”就表示获取根元素下、a元素下、b元素下的多个d元素的id属性的值的集合
5:如果要获取某个需要区分的元素下面的值,那么对于判断使用这样的语法:[属性名=值],属性名和值都不需要加引号,比如:要想获取id=”e1”的e元素下面的f元素的值,就是用这样的表达式:root/a/e$[id=e1]/f。
n此时配置管理模块中读取XML部分的结构示意如图
私塾在线原创精品课程,转载请注明私塾在线【http://sishuok.com/forum/blogPost/list/0/6790.html】