重构指导之一
2014-02-19 13:22
281 查看
一:频繁出现的代码可以使用委托类型的 AOP
类似以下代码在控制器中(在Domain中也有若干)重复出现:
try
{
if (!string.IsNullOrEmpty(categoryId))
{
var model = new ExerciseCategory();
model.ParentId = parentId;
this._exerciseCategoryDal.Update(model);
}
}
catch
{
return 0;
}
return 1;
可重构为:
return ExceptionWrapper.ParseInt(() =>
{
if (!string.IsNullOrEmpty(categoryId))
{
var model = new ExerciseCategory();
model.ParentId = parentId;
this._exerciseCategoryDal.Update(model);
}
});
二:控制器不应放太多逻辑
一段典型代码如下:
public JsonResult GetAuditProcess(string id, int type, string isComplex)
{
var dataTypeEnum = (DataTypeEnum)type;
int dataAuditState;
CategoryAudit categoryAudit;
switch (dataTypeEnum)
{
case DataTypeEnum.Organization:
var org = this._organizationDal.FindOne(new Organization { Id = id });
return this.Json(org, JsonRequestBehavior.AllowGet);
case DataTypeEnum.Project:
var category = new DAL.Project.ProjectCategoryDal().FindOne(new ProjectCategory { Id = id });
dataAuditState = new YHBJ.Domain.Project.ProjectCategoryBll().GetDataAuditState(category);
categoryAudit = new CategoryAudit
{
DataAuditState = dataAuditState,
AuditProcesses = category.AuditProcesses
};
return this.Json(categoryAudit, JsonRequestBehavior.AllowGet);
……省略
}
return null;
}
这个方法存在几个问题:
1:控制器方法内有太多逻辑代码,应重构到 Domain 中去;
2:swtich 中返回的实体不统一,第一个返回的是 organization,其余都是 categoryAudit,这导致无法提炼出方法;
3:虽然有 “尽早返回” 这个原则,但该原则不适用 swtich;
应重构为:
public JsonResult GetAuditProcess(string id, int type, string isComplex)
{
var dataTypeEnum = (DataTypeEnum)type;
CategoryAudit categoryAudit = this._auditProcessor.GetCategoryAudit(id, dataTypeEnum);
return this.Json(categoryAudit, JsonRequestBehavior.AllowGet);
}
其中 ._auditProcessor 是类型 AuditProcessor,被放置到了 Domain 中:
public class AuditProcessor
{
private readonly OrganizationDal _organizationDal = new OrganizationDal();
public CategoryAudit GetCategoryAudit(string id, DataTypeEnum dataTypeEnum)
{
CategoryAudit categoryAudit = null;
int dataAuditState;
switch (dataTypeEnum)
{
case DataTypeEnum.Organization:
var org = this._organizationDal.FindOne(new Organization { Id = id });
categoryAudit = new CategoryAudit
{
DataAuditState = (int)org.AuditState,
AuditProcesses = org.AuditProcesses
};
break;
case DataTypeEnum.Project:
var category = new DAL.Project.ProjectCategoryDal().FindOne(new ProjectCategory { Id = id });
dataAuditState = new YHBJ.Domain.Project.ProjectCategoryBll().GetDataAuditState(category);
categoryAudit = new CategoryAudit
{
DataAuditState = dataAuditState,
AuditProcesses = category.AuditProcesses
};
break;
……省略
}
return categoryAudit;
}
}
public class CategoryAudit
{
public int DataAuditState { get; set; }
public List<AuditProcess> AuditProcesses = new List<AuditProcess>();
}
三:二转手代码不应该出现
除非有明确的规定,比如:在控制中不应该出现 Dal,否则,象下面的二转手代码不应该出现:
public bool Add(ProjectPropSetting projectPropSetting)
{
try
{
this._projectPropSettingDal.Insert(projectPropSetting);
return true;
}
catch (Exception)
{
return false;
}
}
应该直接在控制器重调用 Dal 就可以了。备注:如果带有其它复杂逻辑或者包装了事务等,则应该创建业务逻辑层。
四:不必要的异常包装和处理
上面的代码中还出现了不不要的异常包装和处理,一般的异常应该容许抛出到控制器中,由控制器中的 AOP 代码(见文中一处)进行处理。备注:除非某个特定异常我们就是要处理。
五:不必要的控制器返回信息
类似如下代码没有必要:
public string SaveProjectProp(string isEdit, string projectProp, string id)
{
var prop = new JavaScriptSerializer().Deserialize<ProjectPropSetting>(projectProp);
prop.Id = Guid.NewGuid().ToString().Replace("-", string.Empty);
var flag = new YHBJ.Domain.Project.ProjectPropSettingBll().Add(prop);
if (flag)
{
return "添加成功!";
}
return "添加失败!";
}
可以通过 AOP 包装返回信息,或者甚至是不包装。返回信息一般也是一个 flag,如 0和1,或者 true和false,然后由前台进行判断并处理成友好的信息。
六:事务出现的位置
事务不应该出现在控制器中,如果需要用到事务,它应该在 Domain 或者 Dal 或者直接在 sql 中。出现在 Domain 中的事务,我包装了一下,你可以像下面这样来使用:
TransactionProcessor.Commit(() =>
{
foreach (var item in ls)
{
this._xxxDal.Delete(new LearnCard { Id = item.Id });
}
});
TransactionProcessor 被定义在了 Utility 中,感兴趣者可查看其源码。
七:避免出现魔术字
在代码中不应该出现魔术字,可以使用枚举或者 const 字段来代替它们。如:
this.ViewBag.CredentialsType = prarm.FindAll(paramenter => paramenter.paramenterTypeId == 2004);
this.ViewBag.Nationality = prarm.FindAll(paramenter => paramenter.paramenterTypeId == 3);
this.ViewBag.Politics = prarm.FindAll(paramenter => paramenter.paramenterTypeId == 14);
this.ViewBag.Education = prarm.FindAll(paramenter => paramenter.paramenterTypeId == 6);
this.ViewBag.Degree = prarm.FindAll(paramenter => paramenter.paramenterTypeId == 16);
应该修改为:
this.ViewBag.CredentialsType = prarm.FindAll(paramenter => paramenter.paramenterTypeId == (int)MagicSystemParamenter.CardType);
this.ViewBag.Nationality = prarm.FindAll(paramenter => paramenter.paramenterTypeId == (int)MagicSystemParamenter.Folk);
this.ViewBag.Politics = prarm.FindAll(paramenter => paramenter.paramenterTypeId == (int)MagicSystemParamenter.Politics);
this.ViewBag.Education = prarm.FindAll(paramenter => paramenter.paramenterTypeId == (int)MagicSystemParamenter.STPM);
this.ViewBag.Degree = prarm.FindAll(paramenter => paramenter.paramenterTypeId == (int)MagicSystemParamenter.Degree);
Model 的 Systems 文件夹下存在一个 MagicNumber 文件,专门用于防止你可能觉得无处归类的魔术字。
八:善用匿名类型
如果一个类型只是在控制器中用到,则可以使用匿名类型,如:
return this.Json(new { e = -1, msg = "卡号错误" });
九:避免出现重复代码
目前为止,项目中大家写了不少重复代码,在第一阶段的重构中,我已经尽量消除掉了这些重复代码,接下来不应再出现这些重复代码,除非因为架构需要。
类似以下代码在控制器中(在Domain中也有若干)重复出现:
try
{
if (!string.IsNullOrEmpty(categoryId))
{
var model = new ExerciseCategory();
model.ParentId = parentId;
this._exerciseCategoryDal.Update(model);
}
}
catch
{
return 0;
}
return 1;
可重构为:
return ExceptionWrapper.ParseInt(() =>
{
if (!string.IsNullOrEmpty(categoryId))
{
var model = new ExerciseCategory();
model.ParentId = parentId;
this._exerciseCategoryDal.Update(model);
}
});
二:控制器不应放太多逻辑
一段典型代码如下:
public JsonResult GetAuditProcess(string id, int type, string isComplex)
{
var dataTypeEnum = (DataTypeEnum)type;
int dataAuditState;
CategoryAudit categoryAudit;
switch (dataTypeEnum)
{
case DataTypeEnum.Organization:
var org = this._organizationDal.FindOne(new Organization { Id = id });
return this.Json(org, JsonRequestBehavior.AllowGet);
case DataTypeEnum.Project:
var category = new DAL.Project.ProjectCategoryDal().FindOne(new ProjectCategory { Id = id });
dataAuditState = new YHBJ.Domain.Project.ProjectCategoryBll().GetDataAuditState(category);
categoryAudit = new CategoryAudit
{
DataAuditState = dataAuditState,
AuditProcesses = category.AuditProcesses
};
return this.Json(categoryAudit, JsonRequestBehavior.AllowGet);
……省略
}
return null;
}
这个方法存在几个问题:
1:控制器方法内有太多逻辑代码,应重构到 Domain 中去;
2:swtich 中返回的实体不统一,第一个返回的是 organization,其余都是 categoryAudit,这导致无法提炼出方法;
3:虽然有 “尽早返回” 这个原则,但该原则不适用 swtich;
应重构为:
public JsonResult GetAuditProcess(string id, int type, string isComplex)
{
var dataTypeEnum = (DataTypeEnum)type;
CategoryAudit categoryAudit = this._auditProcessor.GetCategoryAudit(id, dataTypeEnum);
return this.Json(categoryAudit, JsonRequestBehavior.AllowGet);
}
其中 ._auditProcessor 是类型 AuditProcessor,被放置到了 Domain 中:
public class AuditProcessor
{
private readonly OrganizationDal _organizationDal = new OrganizationDal();
public CategoryAudit GetCategoryAudit(string id, DataTypeEnum dataTypeEnum)
{
CategoryAudit categoryAudit = null;
int dataAuditState;
switch (dataTypeEnum)
{
case DataTypeEnum.Organization:
var org = this._organizationDal.FindOne(new Organization { Id = id });
categoryAudit = new CategoryAudit
{
DataAuditState = (int)org.AuditState,
AuditProcesses = org.AuditProcesses
};
break;
case DataTypeEnum.Project:
var category = new DAL.Project.ProjectCategoryDal().FindOne(new ProjectCategory { Id = id });
dataAuditState = new YHBJ.Domain.Project.ProjectCategoryBll().GetDataAuditState(category);
categoryAudit = new CategoryAudit
{
DataAuditState = dataAuditState,
AuditProcesses = category.AuditProcesses
};
break;
……省略
}
return categoryAudit;
}
}
public class CategoryAudit
{
public int DataAuditState { get; set; }
public List<AuditProcess> AuditProcesses = new List<AuditProcess>();
}
三:二转手代码不应该出现
除非有明确的规定,比如:在控制中不应该出现 Dal,否则,象下面的二转手代码不应该出现:
public bool Add(ProjectPropSetting projectPropSetting)
{
try
{
this._projectPropSettingDal.Insert(projectPropSetting);
return true;
}
catch (Exception)
{
return false;
}
}
应该直接在控制器重调用 Dal 就可以了。备注:如果带有其它复杂逻辑或者包装了事务等,则应该创建业务逻辑层。
四:不必要的异常包装和处理
上面的代码中还出现了不不要的异常包装和处理,一般的异常应该容许抛出到控制器中,由控制器中的 AOP 代码(见文中一处)进行处理。备注:除非某个特定异常我们就是要处理。
五:不必要的控制器返回信息
类似如下代码没有必要:
public string SaveProjectProp(string isEdit, string projectProp, string id)
{
var prop = new JavaScriptSerializer().Deserialize<ProjectPropSetting>(projectProp);
prop.Id = Guid.NewGuid().ToString().Replace("-", string.Empty);
var flag = new YHBJ.Domain.Project.ProjectPropSettingBll().Add(prop);
if (flag)
{
return "添加成功!";
}
return "添加失败!";
}
可以通过 AOP 包装返回信息,或者甚至是不包装。返回信息一般也是一个 flag,如 0和1,或者 true和false,然后由前台进行判断并处理成友好的信息。
六:事务出现的位置
事务不应该出现在控制器中,如果需要用到事务,它应该在 Domain 或者 Dal 或者直接在 sql 中。出现在 Domain 中的事务,我包装了一下,你可以像下面这样来使用:
TransactionProcessor.Commit(() =>
{
foreach (var item in ls)
{
this._xxxDal.Delete(new LearnCard { Id = item.Id });
}
});
TransactionProcessor 被定义在了 Utility 中,感兴趣者可查看其源码。
七:避免出现魔术字
在代码中不应该出现魔术字,可以使用枚举或者 const 字段来代替它们。如:
this.ViewBag.CredentialsType = prarm.FindAll(paramenter => paramenter.paramenterTypeId == 2004);
this.ViewBag.Nationality = prarm.FindAll(paramenter => paramenter.paramenterTypeId == 3);
this.ViewBag.Politics = prarm.FindAll(paramenter => paramenter.paramenterTypeId == 14);
this.ViewBag.Education = prarm.FindAll(paramenter => paramenter.paramenterTypeId == 6);
this.ViewBag.Degree = prarm.FindAll(paramenter => paramenter.paramenterTypeId == 16);
应该修改为:
this.ViewBag.CredentialsType = prarm.FindAll(paramenter => paramenter.paramenterTypeId == (int)MagicSystemParamenter.CardType);
this.ViewBag.Nationality = prarm.FindAll(paramenter => paramenter.paramenterTypeId == (int)MagicSystemParamenter.Folk);
this.ViewBag.Politics = prarm.FindAll(paramenter => paramenter.paramenterTypeId == (int)MagicSystemParamenter.Politics);
this.ViewBag.Education = prarm.FindAll(paramenter => paramenter.paramenterTypeId == (int)MagicSystemParamenter.STPM);
this.ViewBag.Degree = prarm.FindAll(paramenter => paramenter.paramenterTypeId == (int)MagicSystemParamenter.Degree);
Model 的 Systems 文件夹下存在一个 MagicNumber 文件,专门用于防止你可能觉得无处归类的魔术字。
八:善用匿名类型
如果一个类型只是在控制器中用到,则可以使用匿名类型,如:
return this.Json(new { e = -1, msg = "卡号错误" });
九:避免出现重复代码
目前为止,项目中大家写了不少重复代码,在第一阶段的重构中,我已经尽量消除掉了这些重复代码,接下来不应再出现这些重复代码,除非因为架构需要。
相关文章推荐
- 随身wifi wifi万能钥匙带来的安全问题
- 2107 图的深度遍历
- IE图片滚轮放大缩小图片
- 粗糙的iOS笔记之数据存储
- “当前不会命中断点。源代码与原始版本不同”的问题的解决方案
- 11章 继承和多态
- 为什么 ["1", "2", "3"].map(parseInt) 返回 [1,NaN,NaN]?【转】
- UVa 40均匀的生成器
- Maven 入门 (听Q有感笔记)
- 使用吉布斯采样求解LDA模型
- Maven 入门 (听Qunar有感笔记)
- web design tools
- 黑马程序员----IO(Properties集合)
- jquery ajax return没有返回值的解决方法
- 用node.js(socket.io)实现数据实时推送
- Javascript延迟执行函数
- 25 个免费的 HTML5 CSS3 jQuery 下拉菜单,有图有真相,看图更直观!
- CUGB图论专场2:The Bottom of a Graph 强连通Tarjan算法
- 黑马程序员_JAVA 学习笔记21 WEB篇8
- Standby and suspend on memory