没有任何量度规矩比得上见识广博者的直觉。我们只会告诉你一些迹象,它会指出“这里有一个可以用重构解决的问题”。
重构的前提
你可以不用TDD开发,但是当你打算开始重构你的代码的时候,一定要为你的代码写单元测试。构建安全网是日常重构的基础,你会不断去重构你的代码,因为没有人能在开始就写出完美的代码,小步重构,运行测试,通过继续,异常回退。这是正常的重构流程,你可能在一天的重构中,运行几十次上百次的单元测试,这是正常的节奏,大刀阔斧的重构是万恶的根源。
当你在团队里做开发的时候,最好的重构方式是持续集成,重构完一点,集成到master。要保证你的分支永远不要和主分支冲突太大。写完一点就提交一个commit,保持修改的原子性,在团队协作中会有意想不到的好处。
1.函数命名
这一点对所有人来说都是,但是简单的事情做起来可并不容易。仔细想想,你上次在代码中写注释是什么时候?可能你是个勤于写注释的人,为了保证自己的程序能被理解,你愿意付出相应的时间来写一段话解释你的程序。但是有没有另一种方式来更好的解释你的程序呢?答案是有的,就是使用函数命名,在Martin Fowler看来,在任何使用注释的地方都可以使用提炼函数加上一个优秀的函数命名来代替你的注释。不必担心函数的命名过长,有时候像说一段话来命名你的函数,是一件相当有难度的事情。
我在日常工作中使用的函数以及命名:
private static boolean isNodeRoleMaster(InstanceNodePO instanceNodePO) {
return NodeRoleType.MASTER.equals(instanceNodePO.getRole());
}
private void changeOperationInstanceStatusToRunning(InstancePO instanceDO, InstanceStatus instanceStatus,String operator) {
instanceService.updateInstanceStatus(instanceDO.getId(),InstanceStatus.RUNNING);
}
有些命名很长,但是在它被调用的地方,可以一目了然的了解它所作的事情。
2.提炼函数
上一点所讲的,当你有写注释的地方,就说明你该提炼函数了。也许对于大多数人,包括我自己做不到像Martin Fowler说的保证函数的行数在6行,一旦超过了6行,代码就开始散发恶臭了。但是遵循一个原则是没错的,“将意图与实现分开”。你可以不断的去重构你的代码,每天重构一点点,这样你的代码就会越来越好。
3.重复代码
我在日常工作中,有个发现,只要你注意审视下你的代码,一定会有重复的代码出现。虽然我们每天都在提示自己Don‘t Repeat Yourself,但是你总是会落入这个怪圈。我们在写代码的时候,总是会提示自己去使用多态继承,但是也许在参数执行的传入的结构发生变化的时候,业务流程有所差异的时候,往往会重复自己之前的代码。当发现有相似代码的时候,尝试移动语句,提炼出相同的代码。
4.循环语句
大量的循环语句有时候往往可以使用多态的形式来代替,直接用以个例子来解释吧
比方说我们有之下一个实际的例子:
public class HandleMessage {
private HandleService handle;
public void process(Type type) {
switch (type) {
case CREATE:
handle.handleCreate();
break;
case DELETE:
handle.handleDelete();
break;
case START:
handle.handleStart();
break;
default:
}
}
}
enum Type {
/**
* Instance operation
*/
DELETE,
CREATE,
START
}
class HandleService {
void handleCreate(){
System.out.println("handleCreate");
}
void handleDelete(){
System.out.println("handleDelete");
}
void handleStart(){
System.out.println("handleStart");
}
}
当操作用来越多的时候,就需要越来越多的switch
判断语句去处理,如果尝试着用枚举的多态去处理它,可能会大大简化之上的代码。
public class RemoveSwitchHandleMessage {
HandleService handleService;
void process(OperationType type){
type.handleMessageHandler(handleService);
}
}
enum OperationType {
/**
* Instance operation
*/
DELETE{
@Override
void handleMessageHandler(HandleService handleService){
handleService.handleDelete();
}
},
CREATE{
@Override
void handleMessageHandler(HandleService handleService){
handleService.handleCreate();
}
},
START{
@Override
void handleMessageHandler(HandleService handleService){
handleService.handleStart();
}
};
abstract void handleMessageHandler(HandleService handleService);
}
当然如果使用更高级的写法可以如之下所示:
enum EnumType{
/**
*
*/
CREATE(HandleService::handleCreate),
START(HandleService::handleStart),
DELETE(HandleService::handleDelete);
public void handleMessage(HandleService handleService,Map map) {
consumer.accept(handleService,map);
}
private BiConsumer<HandleService,Map> consumer;
EnumType(BiConsumer<HandleService, Map> consumer) {
this.consumer = consumer;
}
}
总结
重构的手法有很多,我们还可以使用构造器注入
来代替依赖注入。用构建器模式
来替代大量set,使用静态工厂方法
来替代构造器等等较高级用法。当然在学会用这些模式与高级手法之前,我们先使用简单的手法去重构我们的代码,只要我们平时多多留心,多去动手,都能使我们的代码变好那么一点点,而这些积累起来就将变成有意义的事情。
网友评论