聊聊代码优化——感谢马丁花(Martin Fowler),感谢N多书的作者!

6786 次阅读 by 九九 2014-03-09 | 标签:数据库设计 Oracle TDD 问题 C# Java PHP php 总结

大二那会儿在QQ群里听到有“设计模式”、“测试驱动开发”等软件设计及软件工程类的知识字眼,出于好奇,我还是很认真的去Google了相关词汇的解释。可能也是了解了一些关于设计类的话题,自己也开始对“写代码”这活,有一点往“艺术性”方向理解的意识,而不是ACM的题海战,或是CMD里那很有频率闪动的光标而已。 读完了马丁花大神的《Patterns of Enterprise Application Architecture》后,又读了他的《Refactoring》。我好像有点墙头草的意思,那会儿天天脑子里在想怎么去运用这些大神的利器,哪怕是只写了两个豪不相干的类,也要想那么几分钟,看看这俩货有没有缊藏着什么深厚的模式~哈哈,反正当时是有点过头~后来的代码时间里,自己也在慢慢总结复习了之前看过的那些书本,然后我开始去用《测试驱动开发(Tdd)》里的“一步一个脚印”的思路,再去结合《Refactoring》里提到的“重构:即在保持现有代码功能不变的情况下,改善现有代码。”慢慢的,我好像有点把住什么时候应该去做优化的时机了。还是基于原来老前辈们总结的几个点:
  1. 刚开始的代码可以粗造无比,但要尽可能的优化目前那些简单的优化项目,如:方法命名,变量命名等。
  2. 最小化的代码开支入手,如:如果没有发现有公用的情况的话,所有的属性或方法全是private,当遇到真正需要公用的时候才去更新方法的作用域属性,如:private改成protected,protected还满足不了使用的情况下再去把protected改成public。
  3. 使用查觉重复代码段的方法来提取公用方法,当然你也可以按《Refactoring》里面所描述的按功能、业务的独立性来做,不过我觉得像刚入代码界的新人,代码经验还不充足,对于业务上的理解还存在比较多的内容,或是说,不太清楚哪一块是可以划分出来独立业务的,所以我觉得按重复代码段的拆分可能是一个比较容易找到的拆分入口点。
  4. 时刻保持优化的警界性,提示一下,如果你能做出一点小优化,那就说明了你手上的活又艺术性了一点,所以你是想做有艺术的事情呢?还是想做机器一样的事情呢?这个点你自己选择,不多解释 :D
  5. 用上测试驱动开发的工具,帮助你找到优化的自信。优化就意味着要改掉原来的代码,那么改动之后就会问一个问题“你能保证改动是不会对当前功能或是其它的业务功能没有影响吗?”So~你会用什么来回答?ok,其实最简单的就是在写代码的时候,用上一堆的测试工具,像java里的JUnit,C#里的NUnit,PHP里有PHPUnit,一堆好用的。特别推荐C#里的同学用“TestDriver.NET”灰常的嗨,齐成右键菜单功能哦~ Windows的便捷性你应该懂的~
  6. 差不多就这些,最后是注意保持缩进的好习惯,整洁性越高,越能让你发现优化的可能!:p
最后上一段重构的代码,这段代码为加载关联模块到页面中显示,如:班级里的学生,当我们显示学生列表的时候需要加载它对应的班级出来,那么这里就需要去关联班级的数据(PS:通常情况下我会拒绝使用join left/inner 之类的SQL来做关联的事情,同学你可以去查查相关的内容此文不扯这一话题)。第一版代码:
/**
 * 加载所属班级Map
 *  
 * @author xjiujiu 
 * @throws SQLException SQL异常
 */
@SuppressWarnings("unchecked")
protected void _assignParentMap() throws SQLException
{
    ClassModel class 		= new ClassModel();
    _request.setAttribute(
        "parent_id_map", 
        ArrayUtils.turnListMapToMapMap(
            "id", 
            class.getAllRecords(SqlUtils.whereIn(
                "id",
                "parent_id",
                (List>)_request.getAttribute("list"))
            )
        )
    );
}
  做到后面,又出来了部分下会有员工的情况,同一类型的业务。于是这个时候复制出现了,上面的代码当时想也没有想,直接就复制加小修改成了这样:
/**
 * 加载所属部门Map
 *  
 * @author xjiujiu 
 * @throws SQLException SQL异常
 */
@SuppressWarnings("unchecked")
protected void _assignParentMap() throws SQLException
{
    DepartmentModel department 	= new DepartmentModel();
    _request.setAttribute(
        "department_id_map", 
        ArrayUtils.turnListMapToMapMap(
            "id", 
            department.getAllRecords(SqlUtils.whereIn(
                "id",
                "department_id",
                (List>)_request.getAttribute("list"))
            )
        )
    );
}
通过重构优化后的代码成了这样:
/**
 * 加载所属上级Map
 *  
 * @author xjiujiu 
 * @param  model 数据操作层对象
 * @param  linkField 关联字段
 * @param  list 需要处理的数据列表
 * @throws SQLException SQL异常
 */
protected void _assignLinkModelMap(Model model, String linkField, List> list)
    throws SQLException
{
    if(null == list || 1 > list.size()) {
        return;
    }
    _request.setAttribute(
        linkField + "_map", 
        ArrayUtils.turnListMapToMapMap(
            "id", 
            model.getAllRecords(SqlUtils.whereIn("id", linkField, list))
        )
    );
}
上面的两个方法也就变成了各自的一行调用:
//加载班级关联Map
_assignLinkedModelMap(new ClassModel(), "parent_id", list);
//加载部门关联Map
_assignLinkedModelMap(new DepartmentModel(), "department_id", list);
哈哈,如果以后还有个什么关联,这些方法完全可以搞定所有这块的业务~世界清静了,升华一次,获得经验点,准备升级中..... :p

如果同学你有啥子意见,敬请批斗!欢迎交流中...


评论(3)

暂无评论!


PS:多打字可以减肥哦~234字以内。支持表情:


Top