摘要
-
层:向上一层提供接口,调用下一层的方法
-
泛型:不要使用下层的类或接口作为泛型,这样做会将下层暴露给上层
本文通过三次设计,逐步深入讨论设计方案。
考虑一个简单的RCP项目(SWT,AWT,WEB同理)
-
表格数据从一个xml文件中导入(或其他来源)。
-
可以添加、删除、修改数据
-
可模糊查询定位到某几条数据
-
可将上述表格数据写回来源文件(例如xml文件)
-
点击列名可做排序
分析
业务逻辑很简单,实现起来也许有很简便的方法,例如:将xml作为数据源,用delphi之类的开发工具快速画表格,双击x控件产生事件,在事件方法中写代码…..
现在从设计的角度去考虑
第一次设计
元数据层
这一个股东类的pojo
持久层
-
Read()方法从底层获取数据(读xml文件),得到一个全局map
-
Find()方法查找一条数据
-
Delete()方法删除一条数据
-
Writeback()方法将全局map写回xml文件
-
Update()用于更新一条数据
-
考虑到以上方法都是对map的操作,所以在抽象类中实现
视图层
用于产生table(表头以及数据表体)
注:表现层最外层shell包含"添加"、"删除"、"导入"、"保存"、"搜索"方法,这里省略了这个类的类图
为什么要这么设计
-
分离3层
-
持久层做了 抽象,当以后有其他table时,可以继承XmlServiceDefaultImpl以复用
-
表现层也抽象出来了一般方法,实现写到抽象函数中
上述设计存在的问题
表体属于"数据",那么表头呢?在StockholderInfoTable类中一个个写太麻烦了
考虑表现层的"添加"方法,表现层在table中添加了一条数据,表现层不应知道这条数据是什么数据,它直接告诉持久层:"添加一条数据,封装在一个arraylist中"。这个arraylist就是表现层和持久层的数据接口
第二次设计
元数据层
-
表头信息作为动态数据, 封装在getChineseName中了
-
表现层需要的是array,因此这里提供个将数据转换为string[]的toStringArr方法
持久层
持久层增加了
-
queryAsIdArr:arraylist,用来通过id关键字查询得到arr
-
transFromarrToMap ,表现层提交的arraylist数据转换成map
表现层没动
改变了什么:
完善了数据流向
缺陷
-
"表头信息作为动态数据, 封装在getChineseName中"认真思考一下这个做法,底层应只提供数据,表头属于表现。
-
表现层和元数据层之间仍存在耦合
改进
向上一层提供接口,调用下一层的方法。
元数据层
再次回到pojo
持久层
-
增加一个Dynabean类,提供给上层作为接口,所有方法的参数都是这个Dynabean
-
Dynabean有2个属性,arrattibute1是id的数组,arrattibute2是对应的中文名
-
抽象类取消泛型T: 这里用泛型只会让顶层知道 元数据层的类型
视图层
这里使用泛型,因为抽象出来dynabean,initTable(T)、initTableData(T)方法都只与dynabean打交道,省去了很多table的实现方法