一、为何要重构
1、重构让代码更易阅读和理解。
2、重构改进软件设计
我个人认为,上述两点完全可以是重构的动力。
二、什么情况需要重构
1.重复代码
2.过长函数
3.过大的类
4.过长参数列
5.违反单一职责原则(即有多个理由去修改一个类)
6.散弹式修改(如果每遇到某种变化,你都必须在许多不同的类做出许多小修改,就应该考虑提到一个类中)
7.数据泥团(如果在很多地方看到相同的三四项数据:两个类中相同的字段、许多函数中相同的参数。就可以把他们提到单独类中)。
8.switch惊悚现身(看见switch可用多态来替换)
9.令人疑惑的临时变量(一般复杂算法中会出现不止一个的临时变量,就会产生这样的问题,书中建议提到一个单独类中去)
三、重构手法
以函数对象取代函数(Replace Method with Method Object)
场景:你有一个大型函数,其中局部变量的使用让你无法采用Extract Method。
用法:将这个函数放进一个单独的对象中,如此一来局部变量就变成了对象内部的字段。然后你可以在类里面将大型函数分解为多个小型函数。
例子:
Class Order{
double price(String parm){
double primaryBasePrice;
double basePrice;
double price;
.... //other code
this.mthod();
}
}
我们可以给他转换成以下的样子:
Class Order{
double price(String param,Order sourceOrder){
return new PriceHandle(param,sourceOrder).compute();
}
}
Class PriceHandle{
double primaryBasePrice;
double basePrice;
double price;
String param;
Order order;
public PriceHandle(String param,Order sourceOrder){
this.param=param;
this.order=sourceOrder;
}
public double compute(){
otherMethod();
.... //code1
return order.method();
}
public void otherMethod(){
.... //code2
}
}
文中重点摘要:
替换算法(Subsittue Algorithm)
String checkPerson(String[] people){
for(int i=0;i<people.size();i++){
if(people[i].equals("Don")){
return "Don";
}
if(people[i].equals("Son")){
return "Son";
}
if(people[i].equals("Men")){
return "Men";
}
}
return "";
}
这种代码确实很常见,反正我是写过,其实我们可以替换为下面这一种:
String checkPerson(String[] people){
List candidates=Arrays.asList("Don","Son","Wen");
for(int i=0;i<people.size();i++){
if(candidates.contain(people[i]){
reutrn people[i];
}
}
return "";
}
算法也应该清晰明确易改易读。
搬移函数(Move Method)
场景:在一个类中,函数使用另一个对象的次数比使用所驻对象的次数还多。就应该把函数搬移过去。本着“这个函数与哪个对象交流更多”的原则。
封装集合(Encapsulate Collection)
个人理解用例:
Person person=getPerson();
Set courses=person.getCourses();
courses.add(new Course("体育课"));
应该改为:
Person person=getPerson();
person.addCourse(new Course("体育课"));
//然后要把person返回的课程改为不能修改的集合
public Set getCourses(){
return Collections.unmodifiableSet(courses);
}
以函数取代参数
这个重构的意义在于,一个方法,既可以用参数传递的方式来获取参数,也可以在方法内调用方式来获取参数。那么我们就采用后者,因为过多的参数会增加方法的复杂度。
getDiscountLevel()能直接放在discountedPrice内部调用,所以我们就可以直接拿进去。这其实也是高内聚的一种表现。
提炼子类
类中的某些特性只被某些实例用到。意思就是说一个类中的有些方法,并不是所有实例都必须要的,那么可以创建个子类,然后把这些“非公共方法”移到子类去。然后需要用这些方法的类就用子类就行了。