重构的目的是提高代码的质量,清晰度和可维护性。 从别人的项目中接手过来的陌生的代码库,看里面的代码,总有种眼花缭乱的感觉,或许是因为他不符合自己的风格,又或许它真的很烂,不管怎么样,看过后,自己的想法是,能不能用更好的方法将他实现?苦于无重构的经验,于是乎开始了重构的学习。

开始重构

1.方法重命名

一个最简单最有效的重构是:重命名一个属性/属性,方法或对象。
一个有意义的命名,可以避免很多代码注释,使代码更清晰更易理解。重命名是重构里面最基本的重构技术
,命名依赖于项目描述,以确保开发人员知道一看它究竟是什么。

2.解释变量

如果有一个复杂的表达式(比如,if语句通常有一个罗里吧嗦的条件组),应该将条件赋值到一个临时变量,并给它一个描述性的标识符。

例如:

unless "This is a String with some CAPS".scan(/([A-Z])/).empty?
  puts "capitalised text was found"
end

重构后:

caps_not_found = "This is a String with some CAPS".scan(/([A-Z])/).empty?

unless caps_not_found
  puts "capitalised text was found"
end

3.一个方法在另一个方法中调用

很多时候,一个公用的方法,往往很多其他的方法需要调用,然后每个方法都将这个公共方法赋值,更多的时候,赋值的变量名像那王大娘的裹脚布。

例如:

def add_stuff
  1 + 1
end

def do_something
  temp_variable_with_descriptive_name = add_stuff
  puts "Number is #{temp_variable_with_descriptive_name}"
end

重构后:

def add_stuff
  1 + 1
end

def do_something
  puts "Number is #{add_stuff}"
end 

4.变量分开赋值

项目中经常出现一个变量赋值不止一次,并且每次赋值后,变量的意义都不一,这有悖SRP(单一职责原则)

例如:

temp = 2 * (height + width)
temp = height * width

重构后:

perimeter = 2 * (height + width)
area = height * width

5.链接方法代替调用

如果你有一个临时变量保存调用对象的方法的结果,并临时进行多次的方法调用,那么你应该考虑链接的方法调用来代替。

例如:

class College
  def create_course
    puts "create course"
  end

  def add_student
    puts "add student"
  end
end
  
temp = College.new
temp.create_course
temp.add_student
temp.add_student
temp.add_student

重构后:

class College
  # static method so can be accessed without creating an instance
  def self.create_course
    college = College.new
    puts "create course"
    college # return new object instance
  end

  def add_student
    puts "add student"
    self # refers to the new object instance
  end
end
  
college = College.create_course
          .add_student
          .add_student
          .add_student

6.提取方法

实现是非常简单的。就是将过长的方法它,过于复杂的模块提取到具有描述性标识的新方法。

例如:

class Foo
  attr_reader :bar

  def initialize bar
    @bar = bar
  end

  def do_something
    puts "my baz" # notice this is duplication
    puts bar
  end

  def do_something_else
    puts "my baz" # notice this is duplication
    puts "Something else"
    puts bar
  end
end

重构后:

class Foo
  attr_reader :bar

  def initialize bar
    @bar = bar
  end

  def do_something
    baz
    puts bar
  end

  def do_something_else
    baz
    puts "Something else"
    puts bar
  end

  def baz
    puts "my baz"
  end
end

7.方法对象替代方法

您可能会遇到,你必须要使用提取方法,但临时局部变量的数目实在是太大了。要解决此问题,要做的第一件事是创建一个长的方法来命名新类并添加临时本地变量作为类/对象的属性/属性。

例如:

class Foo
  def bar
    puts "We're doing some bar stuff"
  end

  def baz(a, b, c)
    if a == 'something'
      # do something
    end

    if b == 'else'
      # do else
    end

    if c == 'none'
      # do none 
    end
  end
end   

重构后:

class Foo
  def bar
    puts "We're doing some bar stuff"
  end
end

class Baz
  attr_accessor :a, :b, :c

  def initialize(a, b, c)
    @a = a
    @b = b
    @c = c

    if a == 'something'
      # do something
    end

    if b == 'else'
      # do else
    end

    if c == 'none'
      # do none
    end
  end
end

8.Collection Closure 方法替换 Loop

这个是我以前经常用的方式,要从一堆数据中提取出需要的内容放到一个新数组,我的惯用法是先声明一个空数组,然后对数据迭代。总感觉这样非常丑陋。

例如:

managers = []
employees.each do |e|
    managers << e if e.manager?
end

重构后:

managers = employees.select { |e| e.manager? }

###9.提取公共方法

当在两个单独的类中有重复的代码,那么最好提取重复的代码到一个超类,rails不是有个思想叫DRY(不要重复自己),并将它用于在多个地方。

例如:

class Person
  attr_reader :first_name, :last_name

  def initialize first_name, last_name
    @first_name = first_name
    @last_name = last_name
  end

end

class MalePerson < Person
  # This is duplicated in the `FemalePerson` class
  def full_name
    first_name + " " + last_name
  end

  def gender
    "M"
  end
end

class FemalePerson < Person
  # This is duplicated in the `MalePerson` class
  def full_name
    first_name + " " + last_name
  end

  def gender
    "F"
  end
end

重构后:

class Person
  attr_reader :first_name, :last_name

  def initialize first_name, last_name
    @first_name = first_name
    @last_name = last_name
  end

  def full_name
    first_name + " " + last_name
  end
end

class MalePerson < Person
  def gender
    "M"
  end
end

class FemalePerson < Person
  def gender
    "F"
  end
end

原文:Refactoring Techniques