重构指导之一

简介: 一:频繁出现的代码可以使用委托类型的 AOP 类似以下代码在控制器中(在Domain中也有若干)重复出现: try {     if (!string.IsNullOrEmpty(categoryId))     {         var model = new ExerciseCategory();         model.

一:频繁出现的代码可以使用委托类型的 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 = "卡号错误" });

 

九:避免出现重复代码

目前为止,项目中大家写了不少重复代码,在第一阶段的重构中,我已经尽量消除掉了这些重复代码,接下来不应再出现这些重复代码,除非因为架构需要。

Creative Commons License本文基于 Creative Commons Attribution 2.5 China Mainland License发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名 http://www.cnblogs.com/luminji(包含链接)。如您有任何疑问或者授权方面的协商,请给我留言。
目录
相关文章
|
canal 关系型数据库 MySQL
重构方案设计
重构方案设计
100 0
|
搜索推荐 安全 数据挖掘
产品运营方法论:从目标拆解到策略重构
本文从产品运营的定义到作者对产品运营的理解以及一些工作中用到的方法论做了总结。
211207 33
|
设计模式 算法
重构,避免重构误区
重构,避免重构误区
41 0
|
开发者
工作一年,我重新理解了《重构》
重构是一种在不改变代码本身执行效果的前提下,让代码变得更加整洁易懂的方式。代码不仅要让机器能够实现预期的处理逻辑,更要能够面向开发人员简洁易懂,便于后期维护升级。
367 6
|
设计模式
重构·改善既有代码的设计.04之重构手法(下)完结
重构改善既有代码的设计完结篇,汇总了全部的重构手法。看看哪些手法对你的项目能有所帮助…
7405 2
重构·改善既有代码的设计.04之重构手法(下)完结
|
数据处理
《重构2》第六章-重构基础
《重构2》第六章-重构基础
306 0
|
设计模式 安全 Java
没有测试驱动开发、重构、简单设计及结对编程的敏捷只是虚有其表
  与过去 70 年间大多数程序员的做法相比,本章描述的实践有着根本的区别。它们强 制进行大量的分钟级甚至秒级、深刻的、充满仪式感的行为,以至于大多数程序员初次接 触时都会觉得荒唐。于是许多程序员做敏捷时尝试去掉这些实践。然而他们失败了,因为 这些实践才是敏捷的核心。没有测试驱动开发、重构、简单设计及结对编程的敏捷只是虚 有其表,起不到作用。   测试驱动开发是一个足够复杂的话题,需要一整本书才能讲完。本章仅仅是一个概览, 主要讨论使用该实践的理由和动机,而不会在技术方面进行深入的讨论。特别说一下,本 章不会出现任何代码。   程序员是一个独特的职业。我们制造了大量文档,其中包含深奥的技术
160 0
|
敏捷开发 测试技术