关于代码如何组织的疑惑

刚入行,接触的项目不多,第一次接触的一个SSH项目是这样分层的
抽象一个Dao接口,这个接口包含对象基本增删改查,然后提供一个Dao实现(比如叫Support),至此Dao层结束,然后业务层接口继承Dao接口,业务层继承Support。然后每一个模块一个Action.这样做一个好处就是直接通用一个Dao,不用每个业务类都写一个Dao。但坏处就是因为涉及到泛型,每个个数据表都要对应一个业务对象。如果数据库中有很多的表,就会有很多业务接口业务实现。
具体结构看贴图:

另一个SSH项目是这样分的:
每个模块各一个增删改查Dao加Dao实现,Dao之前互相交错。

问题:个人觉得这两种设计都不好,那么该如何设计,还有,这两个项目中的业务层代码跟Dao层代码感觉都差不多,比如有一个业务层的代码是这样的:
public void deleteIp(Filterip ip){

    deleteDao.deleteIp(ip);
}

public void deleteDev(Devinfo devinfo){

    deleteDao.deleteDev(devinfo);
}

public void deleteBackup(Backup bp){

    deleteDao.deleteBackup(bp);
}

public void deleteDevdetail(Devdetail devdetail){

    deleteDao.deleteDevdetail(devdetail);
}

那这样分逻辑层有什么意义呢,然后最繁重的是action,判断都写在Action方法里面,导致一个方法少则一百多行,多则几百行,一个类上千行。

4个回答

[code="java"]
public String importFile() {
// TODO Auto-generated method stub

this.flag="import";
//从此处开始属于预先校验部分。
//这部分校验的全部放到一个StrutsUtils这样的工具类的validateFile方法中。统一返回String,如果为null,则验证成功,不为null,则验证失败,msg为失败信息
if (myFile == null) {
this.msg="导入文件名获取失败!";
return SUCCESS;
}

if (fileName == null || "".equals(fileName)) {
this.msg="导入文件名获取失败!";
return SUCCESS;
}
String[] tempfn=fileName.split("_");
SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddHHmmss");
boolean isImport=true;
try {
sdf.parse(tempfn[0]);
} catch (ParseException e) {
// TODO Auto-generated catch block
isImport=false;
}
if(!isImport){
this.msg="文件名不符合命名规则,请选择正确的备份文件导入!";
return SUCCESS;
}
//从此处结束属于预先校验部分

//下面文件处理部分,放到文件处理帮助类中,也可放到StrutsUtils工具类中。
String localfilePath = ServletActionContext.getServletContext()
.getRealPath("/backup/files");

File imageFile = new File(localfilePath);

if (!imageFile.exists()) {
imageFile.mkdirs();
}

localfilePath += "/" + fileName;

imageFile = new File(localfilePath);

HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = request.getSession();

Object keyname = session.getAttribute("keyname");
Object keyright = session.getAttribute("keyright");

int right = 0;
String pcname="";

if (keyright != null) {
right=Integer.valueOf(keyright.toString());
}
if(keyname!=null){
pcname=keyname.toString();
}
//这里需要业务层处理,直接在action调用
Backup bk=auditlogService.findBackupByName(fileName);
if (!imageFile.exists()) {// 如果文件存在不覆盖,直接返回导入成功

boolean isCopy=auditlogService.importFile(pcname, request.getRemoteAddr(), right, pcname, myFile, imageFile, request.getLocalAddr());

if(!isCopy){
this.msg="导入失败!";
}else{
this.msg="导入完成!";
}

}else{
if(bk==null){//如果文件存在,数据库没有备份记录
//下面若干语句应该放在业务层处理
Backup bkis = new Backup();
bkis.setName(fileName);
bkis.setStatus("0");
bkis.setAuthority(right);
String createtime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
.format(new Date());
bkis.setCreatedate(createtime);

auditlogService.backup(bkis);
}
Auditlog a = new Auditlog();
a.setSn(sn);
a.setInternettype(0);
a.setTypeid(right);
Auditlogtype auditlogtype = auditlogService.findTypeById(right);
if (auditlogtype != null) {
a.setTypename(auditlogtype.getName());
}
a.setCreatedate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
a.setAddress(request.getRemoteAddr());
a.setSubname(pcname);
a.setObjname(request.getLocalAddr());
a.setActionid(9);
a.setActionname("导入");
a.setLevelid(1);
a.setLevelname("一般");
a.setExpandrecord("导入文件:" + fileName+" 文件已存在,不能重复导入!");
a.setResult(1);
auditlogService.save(a);
this.msg="文件存在,不能重复导入!";

}

return SUCCESS;
}
[/code]

Dead_Knight
Dead_Knight 我里面只是加了注释,让你怎么去减少代码。当然代码还是很多啊,呵呵
大约 7 年之前 回复
hxtao001
hxtao001 action中代码还是很多
大约 7 年之前 回复
Dead_Knight
Dead_Knight 实际上Auditlog的保存、Backup处理都是业务层完成的事情,全部放到action中来了。
大约 7 年之前 回复

早上没事,帮你重构下,

你的逻辑是这样的
1、校验是否可导入
1.1、如果失败 直接返回

2、得到图片文件

3、如果文件存在 直接导入成功
3.1、如果文件无备份 备份

4、导入
4.1、导入成功/失败

5、记录审核日志

因此我给你重构第一段 你可以按照相应的路子继续重构
[code="java"]

public String importFile() {

//不使用异常
String errorMsg = canImportFile(); //此处把校验放到里边
if(!StringUtils.isEmpty(errorMsg)) {
this.msg = errorMsg;
return SUCCESS;
}

//或者使用异常
try {
assertCanImportFile();
} catch(ImportException e) {
this.msg = e.getMessage();
return SUCCESS;
}

}[/code]

还有比如
fileName == null || "".equals(fileName)

完全可以使用如apache commons lang包 缩短 如StringUtils.isEmpty(errorMsg)
建议学学apache commons 包

还有如下代码
[code]Auditlog a = new Auditlog();
a.setSn(sn);
a.setInternettype(0);
a.setTypeid(right);
Auditlogtype auditlogtype = auditlogService.findTypeById(right);
if (auditlogtype != null) {
a.setTypename(auditlogtype.getName());
}
a.setCreatedate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
a.setAddress(request.getRemoteAddr());
a.setSubname(pcname);
a.setObjname(request.getLocalAddr());
a.setActionid(9);
a.setActionname("导入");
a.setLevelid(1);
a.setLevelname("一般");
a.setExpandrecord("导入文件:" + fileName+" 文件已存在,不能重复导入!");
a.setResult(1);
auditlogService.save(a); [/code]

可以分为两步
log = populateAuditlog();
auditlogService.save(a);

比如备份也是这样

Backup bkis = new Backup();

bkis.setName(fileName);

bkis.setStatus("0");

bkis.setAuthority(right);

String createtime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")

.format(new Date());

bkis.setCreatedate(createtime);

auditlogService.backup(bkis);

把这些代码抽象到一个方法中

这样你的主逻辑非常清晰

还有你这里边的功能应该放到服务层(如果事务加在服务层) 否则假设备份成功了 但往下执行出问题了 则回滚不了

在action 我们只需要组装我们的数据 然后把数据交给业务层/服务层处理 然后根据返回值/异常决定返回的页面 即action应该代码越少越好。。

jinnianshilongnian
jinnianshilongnian 其实很简单 就是把问题 条理化 然后组织即可 重构是个很好的入门
大约 7 年之前 回复
hxtao001
hxtao001 看你们的代码,赏心悦目,看自己的代码,杂乱不堪啊。
大约 7 年之前 回复

我之前做过类似的这种分层封装,我是这么做的,仅供你参考:
dao接口,如:
BaseDao接口(该接口提供常用的orm操作:save、update、delete、find、findByPage、searchBySQL……)
dao的实现类,如:
BaseDaoHibernate
BaseDaoIbatis
BaseDaoJdbc
这几种实现类各自完成orm框架需要做的常用操作。

service接口,实际上与BaseDao接口差不多,也是常用的增删改查,如:
BaseManager
service实现类,该实现类中注入BaseDao实例变量,完成常用的操作。如:
BaseManagerImpl

每个业务模块均定义自己的业务层、orm层接口,实现类。如:
UserManager extends BaseManager
UserManagerImpl extends BaseManagerImpl implements UserManager

UserDao extends BaseDao
这里以hibernate为例,
UserDaoHibernate extends BaseDaoHibernate implements UserDao

并把UserDao注入到UserManager中。

如果业务逻辑复杂,在业务层接口增加业务层方法,由实现类具体实现。

Action只要注入业务层bean,在具体方法中,做一些简单的预处理,再交给业务层处理业务逻辑

建议你看看springside的源码以及一些其它优秀的基础框架。对你肯定有帮助。只要基础框架封装好了,业务模块做的事情非常少,增删改查这样的简单模块,基本上UserDao、UserManager接口不需要任何其它代码。

当你对基础框架有深入的了解了,再建议你学习领域驱动等系统设计知识……

yunzhu666
yunzhu666 说得很好,学习了
大约 7 年之前 回复

1、分层,action、service、dao,然后每层中各模块代码放在一起
2、分模块,user、order,然后每模块中各曾代码放一起
3、分层,各层有再分模块
4、分模块,各模块中再分层

权衡利弊,根据需要选择

yunzhu666
yunzhu666 编程应该遵循很多比较好的原则: 比如单一职责原则:一个类或一个方法只做一件事情,不要把不相关的功能杂糅在一起,比如显示逻辑和处理逻辑要分开。 还有很多设计模式,刚开始看《设计模式》那本书可能看不懂,建议看看《大话设计模式》,讲得很浅显易懂、幽默风趣、容易吸收,全书看个两三遍以后再看《设计模式》那本书。 另外看看《重构——改善既有代码的设计》那本书,很有好处。
大约 7 年之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问