今天在公司改了一天代码,仅仅是改了dao层组件的一个控制器(负责获取session、管理事务、获取dao实例),涉及到好几个action控制类,由于action的控制模块设计的也比较恶心,一个execute方法一两百行,改起来也是浑浑噩噩,好几层的if..else。
---------------------
先前写servlet+javaBean+jdbc,我把数据库连接、数据库操作组件dao、控制器、对应主要逻辑这么几个模块分的还是比较清晰的,可以自由组合和控制,能很方便的通过继承、覆盖方法来表述特例,但最近新网站用上了struts2和hibernate就反而糊涂了,dao层到底要不要写?action该怎么设计?
---------------------
我觉得通常不好的设计会在扩展和维护时体现出问题来,可我这次的设计在编码阶段就出问题了,不改设计就不好扩展。主要问题还是挺多的,比如:
1.dao层的控制模块设计有问题,构造方法初始化此控制模块时把hibernate的session和事务统统进行了初始化和开启,并通过参数实例化一个对应的dao实例,相互耦合在了一起,以至于在通常事务操作中如果使用其他服务,而服务中又有类似事务,就导致了事务嵌套(写了例子才发现,hibernate的事务不支持嵌套,看来我得研究下他获取session与当前线程的关系了)。2.dao层的某些实现类中涉及了业务逻辑,比如部分字段使用某种服务来生成,或是添加判断账号是否匹配,或是又有什么其他花样,我一直觉得,dao层他就只管最基本的数据库与业务模型之间的写入与生成,不要去夹杂额外的逻辑才好。当然这里似乎也违背了里氏替换原则。3.dao层我设计的所有方法均是以所有业务模型的上层超类为接口,导致从数据库获取业务模型后如果碰到一些非共性的操作,就得经常作类型强制转换,这个不知道怎么解决。4.action控制层无比的乱,我设计成了常见的增删查改各一个,经过层层判断后执行对应的操作,所有业务模型均通过此来操作,带来的问题碰到特例,比如不可以重复某字段的,只得在控制模块里硬生生的加入一个判断if 。很恶心。但是如果我仅仅写好架子,把最终的那块增删查改的逻辑抽象化,让每个业务模型对应一个他的子类,根据自己情况分别实现,是否又太麻烦了,一大堆类......一大堆请求...----------------------
除此之外我还有一些问题:
1.有关里氏替换原则的,假如dao有个方法是查询,dao的某个子类重写了这个方法,过滤掉了一些“不合法”的数据,这就造成了“子类无法替代父类”的情况,所以我就疑惑了,继承和重写,就必然会破坏里氏替换原则??
2.越封装,就越只能适应更窄的使用范围(功能作用愈发的有针对性),我在封装了很多常用功能后一直有这个感觉,最近才发现设计的“粒度”很重要,且很难把握,粒度大了似乎就是造成适用范围缩小的原因,所以在此问问诸位前辈,设计一个方法,应该考虑哪些问题,或是看些什么书比较有帮助??----------------------
最后感谢所有耐心看完并提出意见和建议的朋友!!!!
----------------------
以下是我那无比恶心的action控制层的execute方法的伪代码,boolean success = true;
if (是否在session发现了操作者的对象) {
if (当前操作者是否有权限) {
if (从前台获取的必要数据是否合法) {
if (数据库操作的初始化是否正常) {
if (添加数据到数据库是否成功) {
........
//有时这里可能还会有针对某一种情况的分支而出现一组if else
try {
} catch (......) {
setAttribute("内部服务错误");
writeLog("何时,在添加xx数据时事务提交出错");
success = false;
} catch (......) {
setAttribute("内部服务错误");
writeLog("何时,在添加xx数据时又发生了啥啥啥错误");
success = false;
}
} else {
setAttribute("内部服务错误");
writeLog("何时,在添加xx数据时数据库操作错误");
success = false;
}
} else {
setAttribute("内部服务错误");
writeLog("何时,在添加xx数据时初始化数据库操作单元出错");
success = false;
}
} else {
setAttribute("非法操作");
writeLog("何时,在添加xx数据时前台参数非法");
success = false;
}
} else {
setAttribute("您没有当前操作的权限"); success = false;
}
} else {
setAttribute("登录状态丢失,请重新登录");
success = false;
}
if (success) {
forward ....
} else {
forward ....
}这段代码可怎么优化??
---------------------
先前写servlet+javaBean+jdbc,我把数据库连接、数据库操作组件dao、控制器、对应主要逻辑这么几个模块分的还是比较清晰的,可以自由组合和控制,能很方便的通过继承、覆盖方法来表述特例,但最近新网站用上了struts2和hibernate就反而糊涂了,dao层到底要不要写?action该怎么设计?
---------------------
我觉得通常不好的设计会在扩展和维护时体现出问题来,可我这次的设计在编码阶段就出问题了,不改设计就不好扩展。主要问题还是挺多的,比如:
1.dao层的控制模块设计有问题,构造方法初始化此控制模块时把hibernate的session和事务统统进行了初始化和开启,并通过参数实例化一个对应的dao实例,相互耦合在了一起,以至于在通常事务操作中如果使用其他服务,而服务中又有类似事务,就导致了事务嵌套(写了例子才发现,hibernate的事务不支持嵌套,看来我得研究下他获取session与当前线程的关系了)。2.dao层的某些实现类中涉及了业务逻辑,比如部分字段使用某种服务来生成,或是添加判断账号是否匹配,或是又有什么其他花样,我一直觉得,dao层他就只管最基本的数据库与业务模型之间的写入与生成,不要去夹杂额外的逻辑才好。当然这里似乎也违背了里氏替换原则。3.dao层我设计的所有方法均是以所有业务模型的上层超类为接口,导致从数据库获取业务模型后如果碰到一些非共性的操作,就得经常作类型强制转换,这个不知道怎么解决。4.action控制层无比的乱,我设计成了常见的增删查改各一个,经过层层判断后执行对应的操作,所有业务模型均通过此来操作,带来的问题碰到特例,比如不可以重复某字段的,只得在控制模块里硬生生的加入一个判断if 。很恶心。但是如果我仅仅写好架子,把最终的那块增删查改的逻辑抽象化,让每个业务模型对应一个他的子类,根据自己情况分别实现,是否又太麻烦了,一大堆类......一大堆请求...----------------------
除此之外我还有一些问题:
1.有关里氏替换原则的,假如dao有个方法是查询,dao的某个子类重写了这个方法,过滤掉了一些“不合法”的数据,这就造成了“子类无法替代父类”的情况,所以我就疑惑了,继承和重写,就必然会破坏里氏替换原则??
2.越封装,就越只能适应更窄的使用范围(功能作用愈发的有针对性),我在封装了很多常用功能后一直有这个感觉,最近才发现设计的“粒度”很重要,且很难把握,粒度大了似乎就是造成适用范围缩小的原因,所以在此问问诸位前辈,设计一个方法,应该考虑哪些问题,或是看些什么书比较有帮助??----------------------
最后感谢所有耐心看完并提出意见和建议的朋友!!!!
----------------------
以下是我那无比恶心的action控制层的execute方法的伪代码,boolean success = true;
if (是否在session发现了操作者的对象) {
if (当前操作者是否有权限) {
if (从前台获取的必要数据是否合法) {
if (数据库操作的初始化是否正常) {
if (添加数据到数据库是否成功) {
........
//有时这里可能还会有针对某一种情况的分支而出现一组if else
try {
} catch (......) {
setAttribute("内部服务错误");
writeLog("何时,在添加xx数据时事务提交出错");
success = false;
} catch (......) {
setAttribute("内部服务错误");
writeLog("何时,在添加xx数据时又发生了啥啥啥错误");
success = false;
}
} else {
setAttribute("内部服务错误");
writeLog("何时,在添加xx数据时数据库操作错误");
success = false;
}
} else {
setAttribute("内部服务错误");
writeLog("何时,在添加xx数据时初始化数据库操作单元出错");
success = false;
}
} else {
setAttribute("非法操作");
writeLog("何时,在添加xx数据时前台参数非法");
success = false;
}
} else {
setAttribute("您没有当前操作的权限"); success = false;
}
} else {
setAttribute("登录状态丢失,请重新登录");
success = false;
}
if (success) {
forward ....
} else {
forward ....
}这段代码可怎么优化??
解决方案 »
- strust2中使用urlwrite后ognl表达怎么用不了(急急急)
- EJB3.0 javax.persistence.PersistenceException: 错误。
- Apache2.2.8+SSL双向链路 如何配置??
- 麻烦大家帮我看下,错的地方怎么改?
- struts1.2中 actionform的生命周期
- 读"企业应用架构模式"书,思考struts之mvc所处层,求教
- 请问Spring是不是和hibernate,struts一样有Jar下载啊.....
- 在Struts架构下前台同后台传参数,为什么这样做不行呢?
- 谁知道ejb在weblogic8.1上为什么发布出错???
- 初学者的问题:各位用JAVA主要做哪方面的东西?它最擅长的应用是那些方面。希望有经验的给点意见。
- 小弟新来,在线急等.37度酷暑求回答 struts问题
- MappingException: Resource not found
其实没有必要这么固执:
boolean success = true;
if (未在session发现了操作者的对象) {
setAttribute("登录状态丢失,请重新登录");
return false;
}
if (当前操作者没有权限) {
setAttribute("当前用户无权访问");
return false;
}
if (从前台获取的必要数据不合法) {
setAttribute("数据有异常,请重新输入");
return false;
}
if (数据库操作的初始化正常 && 添加数据到数据库成功) {
........
//有时这里可能还会有针对某一种情况的分支而出现一组if else
try {
} catch (......) {
setAttribute("内部服务错误");
writeLog("何时,在添加xx数据时事务提交出错");
success = false;
} catch (......) {
setAttribute("内部服务错误");
writeLog("何时,在添加xx数据时又发生了啥啥啥错误");
success = false;
}
} else {
setAttribute("内部服务错误");
writeLog("何时,在添加xx数据时数据库操作错误");
success = false;
}
}
return success;
struts2可以用拦截器等实现一些异常应统一处理
不应设在action中给与提示还有,如果有大量的逻辑判断,然后要根据不同的情况返回给页面不同的错误提示,可以在service中
使用抛出自定义异常的方式给与提示,或在service中返回信息到action中,从而在action中
只用拿出那个消息,再给显示在页面上。addFieldError()等错误,有错误就返回INPUT
实际上还有很多其他的问题(如果说真的想要精确的错误信息就不应该以这种形式判断 就算判断的话 详细的错误信息至少也要放到一个常量对象里封装起来啊或者弄一个方法专门根据异常写出不同的错误日志 你这么写 有人会发疯的。。)同情LZ 哀悼LZ 围观LZ 阿门。。
其实Java的这种分工也有其合理之处。并不是贬低楼主能力,但觉得类似的开发如果能找到通用的开源框架,就应该勇敢的舍去现有已经阻碍自己项目的实现,并大胆引入外部组件。
其实只要有着执着的心,有着能理解优秀代码的眼光(感觉),设计就并不痛苦,亦或是一种幸福;如果若干年后回头看自己代码,能感受到当初的那份热诚,其实已经足够,有时并不需要强求。对了给楼主个建议:数据库操作应该是组件层的,而具体应用是交易层的,先把这个分开吧,否则日后组件不能重用,交易亦如此。
回21楼,网站规模其实不算大,业务逻辑也不算复杂,所以没好意思把spring也整上去
一看头都大了 , 现在SSH来写好多了
层次分明 aciton dao service一点也不混乱
网站研发任务时间上不是很充足,如果时间允许的话,我打算这么改:
1.把dao层中的逻辑全部抽出来,并在业务逻辑层中加以封装
2.抽出action中有关权限控制及其他一些常用的逻辑到服务层,尽量使action只做组件与组件之间的调用协调工作,成为一系列组件关系的维持者
3.修改日志系统,输出所有必要的错误异常信息
4.简化部分意义不大的判断和异常设计