随笔 - 6  文章 - 0  评论 - 13  阅读 - 12万

重构实战案例一,以子类取代类型编码(原创)

以子类取代类型编码

 Replace Type Code with Subclasses

1. 何谓重构

 

1.1名词解释

  对软件内部结构的㆒种调整,目的是在不改变「软件之可察行为」前提下,提高其可理解性,降低其修改成本。

  

1.2动词解释

  使用一系列重构准则(手法),在不改变「软件之可察行为」前提下,调整其结构。

 

2. 为何重构

 

2.1「重构」改进软件设计

  同样完成一件事,设计不良的程序往往需要更多代码,这常常是因为代码在不同的方使用完全相同的语句做同样的事。因此改进设计的一个重要方向就是消除重复代码(Duplicate Code)

 

2.2「重构」使软件更易被理解

  你的源码还有其它读者:数个月之后可能会有另一位程序员尝试读懂你的代码并做一些修改。我们很容易忘记这第二位读者,但他才是最重要的。计算器是否多花了数个钟头进行编译,又有什么关系呢?如果一个程序员花费一周时间来修改某段代码,那才关系重大— 如果他理解你的代码,这个修改原本只需一小时

 

2.3「重构」助你找到臭虫 ( bugs)

  Kent Beck 经常形容自己的㆒句话:『我不是个伟大的程序员;我只是个有着些优秀习惯的好程序员而已。』重构能够帮助我更有效地写出强固稳健(robust)的代码。 

 

2.4「重构」助你提高编程速度

  终于,前面的一切都归结到了这最后一点:重构帮助你更快速地开发程序。听起来有违反直觉。当我谈到重构,人们很容易看出它能够提高质量。改善设计、提升可读性、减少错误,这些都是提高质量。但这难道不会降低开发速度吗?我强烈相信:良好设计是快速软件开发的根本。事实上拥有良好设计才可能达成快速的开发。如果没有良好设计,或许某段时间内你的进展迅速,但恶劣的设计很快就让你的速度慢来。你会把时间花在调试面,无法添加新功能。修改时间愈来愈长,因为你必须花愈来愈多的时间去理解系统、寻找重复代码。随着你给最初程序打上一个又一个的补丁(patch),新特性需要更多代码才能实现。真是个恶性循环。

 

3.何时重构?

  重构本来就不是一件「特别拨出时间做」的事情,重构应该随时随地进行。你不应该为重构而重构,你之所以重构,是因为你想做别的什么事,而重构可以帮助你把那些事做好

 

3.1三次法则(The Rule of Three)

  Don Roberts 给了我一条准则:第一次做某件事时只管去做;第二次做类似的事会产生反感,但无论如何还是做了;第三次再做类似的事,你就应该重构。

  ☆ 事不过则重构。(Three strikes and you refactor.

 

3.2重构时机

  添加功能时一并重构

  修补错误时一并重构

  复审代码时一并重构

 

-以上章节摘抄自《重构-改善既有代码的设计

 

4.平台重构案例

 

4.1重构动机

  1. 实例模块为View,重构元素为ViewAction、ViewProcessBean、View,以下为关系图。

  

  2. 由于View存在多种editMode(编辑模式),而每个调用的地方都需要进行type code(类型码)判断,然后再进行相应的业务逻辑处理,最终在每个调用的地方都形成了大量的if-else代码,大大减弱了代码的可读性,和逻辑清晰度。

 

  3. 调用的地方:

  

4.2重构作法

  

 

如上图所示,将每种type code重构成subclass,加强了每种类型处理业务逻辑的能力。

 

View-版本1566代码片段:

 

复制代码
public EditMode getEditModeType() {
if (EDIT_MODE_CODE_DQL.equals(getEditMode())) {
return new DQLEditMode(this);
}
else if (EDIT_MODE_CODE_SQL.equals(getEditMode())) {
return new SQLEditMode(this);
}
else if (EDIT_MODE_DESIGN.equals(getEditMode())) {
return new DesignEditMode(this);
}

return new NullEditMode(this);
}
复制代码

说明:调用者无需了解具体的类型,由View自身作判断,返回EditMode接口,从而实现多态调用。

 

 

ViewProcessBean代码片段:

重构前-版本1503:

 

复制代码
public String expDocToExcel(String viewid, WebUser user, ParamsTable params) throws Exception {
if (view.getEditMode().equals(View.EDIT_MODE_DESIGN)) {
datas
= dp.queryBySQLPage(sql, params, tempPage, LINES, user.getDomainid());
}
else if (view.getEditMode().equals(View.EDIT_MODE_CODE_DQL)) {
datas
= dp.queryByDQLPage(dql, params, tempPage, LINES, user.getDomainid());
}
else if (view.getEditMode().endsWith(View.EDIT_MODE_CODE_SQL)) {
datas
= dp.queryBySQLPage(sql, params, tempPage, LINES, user.getDomainid());
}
}
复制代码

 

重构后-版本1566:

 

复制代码
public String expDocToExcel(String viewid, WebUser user, ParamsTable params) throws Exception {
datas
= view.getEditModeType().getDataPackage(params, tempPage, LINES, user, currdoc);
//其他业务逻辑
}
复制代码

 

 

5.结语

  由上述案例可看到,引入subclass代替type code可以大大减少if-else判断,而且可以把责任内聚到每种type中,使代码结构更清晰易懂。

 

6.其他

       在本案例中引入了空类型概念,即NullEditMode,代码如下:

  

复制代码
/**
*
*
@author nicholas zhen
*
*/
public class NullEditMode extends AbstractEditMode implements EditMode {

public NullEditMode(View view) {
super(view);
}

public String getQueryString(ParamsTable params, WebUser user, Document sDoc) {
return "";
}

public DataPackage getDataPackage(ParamsTable params, WebUser user, Document doc) throws Exception {
return new DataPackage();
}

public DataPackage getDataPackage(ParamsTable params, int page, int lines, WebUser user, Document doc) throws Exception {
return new DataPackage();
}

public long count(ParamsTable params, WebUser user, Document doc) throws Exception {
return 0;
}
}
复制代码

说明:空类型保证了调用每个方法都有默认值返回,而不需要进行非空判断,当View没有类型时,即返回默认的空类型

 

原创人员:Nicholas

posted on   obpm  阅读(1066)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
< 2010年7月 >
27 28 29 30 1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
1 2 3 4 5 6 7

点击右上角即可分享
微信分享提示