之前写了个函数的重构,这里写的是函数的调用的重构,不同哦,是为了写出让别人好调用的函数(或接口)。
1、函数改名
修改点:函数的名称未能提示函数的用途。
做法:修改函数的名称
如果你想给函数写上一句什么注释,那么你就把这个注释想办法作为名称写上好了。
Martin原话:
你可能无法第一次就取一个好名字,这个时候你就会想,就这么将就着吧,毕竟这只是一个名称。
当心,这是恶魔的召唤,是通向混乱之路,千万不要被它诱惑。
(我就无数次被诱惑,然后取了很多渣名,因为想一个好名字真是太难了,除非我把函数名写很长)
2、添加参数
修改点:某个函数需要从调用端得到更多信息
做法:为此函数添加一个对象参数,让该对象带进函数所有信息。
3、移除参数(好吧,相比第二点,很多人可能会嫌麻烦不去搞这个,恶魔的诱惑哦)
修改点:函数本体不再需要某个参数
做法:将该参数去除
4、将查询函数和修改函数分离(所以直接用属性就好了啊)
修改点:某个函数既返回对象状态值,又修改对象状态
做法:建立两个不同的函数,其中一个负责查询,又负责修改
存在例外哦,就是并发场景下同时查询与修改的操作,那么你仍应该分离,但是单独写一个函数去同时进行这两个事情。
5、令函数携带参数
修改点:若干函数做了类似工作,但在函数本体中却包含不同的值
做法:建立单一函数,以参数表达那些不同的值
简单来说,就是两个函数有很多相同部分,就几个值不同,你把这几个值作为函数参数,那么就可以把两个函数合二为一
6、以明确函数替代参数(与5相反哦)
修改点:你有一个函数,其中完全取决于参数值而采用不同行为(看好是完全)
做法:针对该参数的每一个可能值,建立一个独立函数
意思就是说你根据参数的判断而采取不同的行为,那么你完全可以分成几个函数来实现。
而如果影响并不是很大,用5就好了,如果确实需要条件判断,那么可以考虑使用多态来消除条件判断
7、保持对象完整
修改点:你从某个对象中去除若干值,将它们作为某一次函数调用时的参数
做法:改为传递整个对象
动机:万一将来函数需要新的数据项,你就必须查找并修改对此函数的所有调用。而且这样也能提高整个代码的可读性。
但是也有例外:如果你穿的是数值,那么函数就仅仅依赖于数值,但是如果是对象,那么依赖的就是整个对象,这有可能会造成你的结构恶化,所以你得具体情况具体分析。
不过如果一个函数使用了另外一个对象很多的值,那么你可能需要考虑是不是需要把这个函数放在那个对象所属的类里面了。
8、以函数取代参数
修改点:对象调用某个函数,并将所有结果作为参数,传递给另外一个函数
做法:让参数接受者去除该项参数,并直接调用前一个函数
动机:如果函数可以通过其它途径获取参数值,那么它就不应该通过参数取得该值。过长的参数列会增加程序员的理解难度,因此应该尽可能缩短参数列的长度。
9、引入参数对象
修改点:某些参数总是很自然地同时出现
做法:以一个对象取代这些参数
之前在何处重构里已经讲过了,其它的章节貌似也涉及到了。这种类其实也有其他的好处,比如你建立了这样一个类,说不定有些函数就可以放到这个类里,让代码结构更清晰。
10、移除设置函数
修改点:类中的某个字段应该在对象创建时被设值,然后就不再改变
做法:去掉该字段的所有设置函数
意思就是说如果初始化的时候就不需要改变某个字段,那么你就不要去添加设置函数,这样会让意图不明确。
11、隐藏函数
修改点:有一个函数,从来没有被其他任何类用到
做法:将这个函数修改为private
还是这个意思,让调用者看到他们应该看到的,和想看到的,不要暴露给他们过多的信息,越简单越好,他们用起来越方便,也有利于安全性。
12、以工厂函数替代构造函数
修改点:你希望在创建对象时不仅仅是做简单的建构工作。
做法:将构造函数替换为工厂函数
很简单,在数据的重构里第14点我的例子就是这样的。
public class Room { public Room() { } public static Room CreateRoom() { return new Room(); } }
这个东西用来多态去除类型码,去除过多的条件表达式特别有效
也就是在CreateRoom里用来判断Room类型来创建Room的不同子类,当然在类型较少的情况下,你也可以加多个工厂函数,分别创建不同的子类
13、封装向下转型
修改点:某个函数返回的对象,需要由函数调用者执行向下转型。
做法:将向下转型动作移到函数中
简单例子:
public class Room { public Room() { } public Object GetRandRoom() { return RoomList.GetRandRoom(new Random().Next()); } }
应该转为
public class Room { public Room() { } public Room GetRandRoom() { return (Room)RoomList.GetRandRoom(new Random().Next()); } }
也就是说有些系统函数或者别人写的函数经过处理后返回一个object对象,但是你知道这个object对象是Room类型,那么请把它转化为Room类型,也就是说尽量在更底层就转型,而不是在调用端转型,这个增加调用者的理解难度。
这种情况可能会在返回迭代器或者集合的函数身上发生
不过貌似我们.NET几乎不会出现这种情况,起码我遇到的代码就没见过,是我见过的代码太少呢,还是说大家都很厉害的样子,避开了这个坑。
14、以异常取代错误码
修改点:某个函数返回一个特定的代码,用以表示某种错误情况
做法:改为抛异常
好吧这个应该不用我来说了吧,不过很多人(包括我)都习惯返回错误码,因为简单,大家共勉,以图改进吧。
顺便提一点,对.NET的错误机制,也就是try catch finally throw这几个东西用到时候要小心点,这个东西存在很多的争议,就是你抛出的异常应该是可控的异常,而不应该是不知道是什么鬼的异常,如果是不知道是什么鬼的异常就应该立马解决了,而不是吞掉。
15、以条件判断取代异常
修改点:面对一个调用者可以预先检查的条件,你抛出一个异常
做法:修改调用者,使它在调用函数之前先做检查。
好吧,这个东西也就是消除异常,也就是说比如这个异常你可以提前预料到,你就应该去直接用个某种手段去检查,检查不通过就返回你catch后执行的操作,而不是不去检查,直接try catch。坦白说,其实try catch里的代码越少越好,因为找到异常后定位异常也需要资源。