面向对象2 - 重构

158 阅读6分钟

内部状态

  • 注意保护,类的私有成员变量。
  • 私有成员,内部状态。
  • 属性返回内部状态。
  • 方法返回内部状态。

注入

  • 构造注入
  • 属性注入
  • 方法参数注入

  • 类,明确用途。
  • 生命周期,何时创建。
  • 状态变化。
  • 何时销毁。
  • 关联哪些资源,资源的状态变化。
  • 很难找到修改点,修改就容易引入BUG。
  • 过大的类,考虑重构。
  • 考虑,在需求问题中寻找名词,将名词转换为对象。
  • 对象的设计
  • 对象间的关系设计
  • 移动字段,移动方法,
  • 移动方法非常重要,因为方法代表的就是职责。
  • 字段,方法,移动到父类
  • 父类字段,方法移动到具体子类
  • 父类,子类合并在一起
  • 组合取代继承
  • 继承取代组合
  • 相似类,提炼出一个父类
  • 提取类,内联并移除类
  • 用对象取代数值项。 简单的例子,一开始,你可以用简单的字符串表示电话号码。可是到后面,逻辑变多复杂,需要灵活维护扩展,你就需要新建电话号码类对象。

单一职责 SRP

  • 分解长方法,移至短小方法。
  • switch 单独一个方法。
  • 对于循环內多行语句,多个职责,可以考虑提取方法,每个方法都进行循环,执行单个职责。
  • 提取方法之后,重新命名方法內变量,参数的名字。
  • 提取方法之后,观察方法內依赖的对象,方法的意图,思考方法是否仍然属于当前类的职责。
  • 多数情况下,方法依赖什么对象,简单来说,方法的参数,是什么对象,那么方法就应该存在于那个对象所在的类中。
  • 在将方法移动到依赖对象类中后,可能参数不再需要,方法名字继续变化,根据实际进行调整测试通过。
  • switch 语句不要用在另一个对象的某个属性上,最好在属性自己所在对象上使用 switch。
  • 方法再次移动到某个类后,可能需要原类属性作为传入参数调整。
  • 始终记住,职责,意图,单一职责,单一意图。
  • 单一职责,职责暂且就是指方法,职责有大小,职责有粒度,驾驶员开车是职责,开车的具体操作分很多细小的职责。
  • 面对软件开发,初期可能就是从大的职责出发,面对小的职责,可能变化的职责,单独提取出来并封装,保证软件设计的灵活可维护性。
  • 我们将方法都归位之后,通俗讲就是,方法足够小,并居住在他应该在的类中。

我们要开始考虑继承了。。。。

通常适合继承的是,类型,有多少种类型呢,换句话说,有多少个子类呢?

有了继承,子类的关系,我们就可以利用多态,替换掉 switch 判断。

多态,往往更能表达灵活清晰的条件逻辑,switch 判断,if else 判断。

重复代码

  • 相同的程序结构。
  • 同一个类中,两个方法有相同的代码逻辑。
  • 两个类,兄弟子类,含有相同的类似代码逻辑,提取出来,放到父类。这时候,有多个选择,父类一个方法,父类一个默认实现,子类重写,父类做一个模板方法模式,子类重写等。
  • 两个毫不相干的类,出现重复类似代码。提取出来,放在一个新类里面。

方法

方法主要用来,改变对象的状态,或者获取对象的状态。

  • 要把,改变,获取,这两种行为分开。

方法是否是对象的职责

  • 移动方法到正确的对象。

方法太长

  • 类对象方法代码多,说明关注的东西多。
  • 后续的需求变更,修改很麻烦且容易导致问题。
  • 提取分隔更多小方法,我的原则是代码块存在复用,就提取为单独的方法。
  • 方法內的相同功能逻辑块,if,switch,while 等,这些都是可以提取为更小方法的信号。

方法参数太多

  • 方法的参数,原则上,大多数可以在其宿主类中获得。不能获得,考虑方法位置,职责是否符合实际。
  • 参数实在太多,应该传递对象参数。
  • 有个方法,过多的使用另外一个类数据,方法。此时应该把这个方法移动到那个类。
  • 返回值有多个的方法,思考分隔为几个小方法,思考返回一个对象。
  • 考虑,你取对象的属性作为一个方法的参数,对比直接传递这个对象?
  • 考虑,调用一个方法获得返回值,然后把这返回值作为参数传给另一个方法,对比在另一个方法里直接调第一个方法?
  • 考虑,有的方法参数总是一起传递,对比把一起传递的参数封装为一个对象?
  • 函数返回值,尽量是确切类型,不要object,使用泛型很好。
  • 关注,方法的输入
  • 关注,方法內用到的对象字段

方法內局部变量太多

  • 可以考虑,建立一个类,方法对象类。
  • 局部变量,就变成类的私有字段。
  • 原宿主类私有字段,通过原宿主对象传递。
  • 再将原方法,进行提取为更多类的小方法。

方法不公开,就要私有

  • 方法也是对象的成员,对象自己内部行为职责不必暴露,避免外部调用混乱。

通过功能分解分隔方法

  • 功能分解是一种自然的处理复杂问题的方法,所谓大事化小,小事化了。
  • 功能分解,大功能处理步骤,小功能处理步骤,小小功能处理步骤。
  • 功能分解的问题,通常需要主程序控制子程序。
  • 功能分解的问题,应对需求变化的无能为力。

代码发散式变化 代码散乱式变化

依恋情节

将数据和对数据的操作行为包装在一起。

数据泥团

a 字段,b 字段总是一起出现,a 参数,b 参数总是一起出现。 这种情况,就需要为 a,b 封装一个对象。

临时变量,不要重复赋值,重复赋值,说明变量的意图改变,当然除了在循环中。

不要给方法参数赋值。

忌过程耦合,忌封装性差。