Java开发中存在这样的代码,反而影响总体整洁和可读性

不完美的库类

不完美的库类(Incomplete Library Class)程序员

当一个类库已经不能知足实际须要时,你就不得不改变这个库(若是这个库是只读的,那就没辙了)。编程

问题缘由

许多编程技术都创建在库类的基础上。库类的做者没用未卜先知的能力,不能所以责怪他们。麻烦的是库每每构造的不够好,并且每每不可能让咱们修改其中的类以知足咱们的须要。设计模式

解决方法

  • 若是你只想修改类库的一两个函数,能够运用 引入外加函数(Introduce Foreign Method)
  • 若是想要添加一大堆额外行为,就得运用 引入本地扩展(Introduce Local Extension) 。

收益

  • 减小代码重复(你不用一言不合就本身动手实现一个库的所有功能,代价过高)

什么时候忽略

  • 若是扩展库会带来额外的工做量。

重构方法说明

引入外加函数(Introduce Foreign Method)

问题app

你须要为提供服务的类增长一个函数,但你没法修改这个类。ide

class Report {
  //...
  void sendReport() {
    Date nextDay = new Date(previousEnd.getYear(),
      previousEnd.getMonth(), previousEnd.getDate() + 1);
    //...
  }
}

解决函数

在客户类中创建一个函数,并一个第一个参数形式传入一个服务类实例。this

class Report {
  //...
  void sendReport() {
    Date newStart = nextDay(previousEnd);
    //...
  }
  private static Date nextDay(Date arg) {
    return new Date(arg.getYear(), arg.getMonth(), arg.getDate() + 1);
  }
}

引入本地扩展(Introduce Local Extension)

问题spa

你须要为服务类提供一些额外函数,但你没法修改这个类。设计

解决代理

创建一个新类,使它包含这些额外函数,让这个扩展品成为源类的子类或包装类。

中间人

中间人(Middle Man)

若是一个类的做用仅仅是指向另外一个类的委托,为何要存在呢?

问题缘由

对象的基本特征之一就是封装:对外部世界隐藏其内部细节。封装每每伴随委托。可是人们可能过分运用委托。好比,你也许会看到一个类的大部分有用工做都委托给了其余类,类自己成了一个空壳,除了委托以外不作任何事情。

解决方法

应该运用 移除中间人(Remove Middle Man),直接和真正负责的对象打交道。

收益

  • 减小笨重的代码。

什么时候忽略

若是是如下状况,不要删除已建立的中间人:

  • 添加中间人是为了不类之间依赖关系。
  • 一些设计模式有目的地建立中间人(例如代理模式和装饰器模式)。

重构方法说明

移除中间人(Remove Middle Man)

问题

某个类作了过多的简单委托动做。

解决

让客户直接调用委托类。

依恋情结

依恋情结(Feature Envy)

一个函数访问其它对象的数据比访问本身的数据更多。

问题缘由

这种气味可能发生在字段移动到数据类以后。若是是这种状况,你可能想将数据类的操做移动到这个类中。

解决方法

As a basic rule, if things change at the same time, you should keep them in the same place. Usually data and functions that use this data are changed together (although exceptions are possible).

有一个基本原则:同时会发生改变的事情应该被放在同一个地方。一般,数据和使用这些数据的函数是一块儿改变的。

  • 若是一个函数明显应该被移到另外一个地方,可运用 搬移函数(Move Method) 。
  • 若是仅仅是函数的部分代码访问另外一个对象的数据,运用 提炼函数(Extract Method) 将这部分代码移到独立的函数中。
  • 若是一个方法使用来自其余几个类的函数,首先肯定哪一个类包含大多数使用的数据。而后,将该方法与其余数据一块儿放在此类中。或者,使用 提炼函数(Extract Method) 将方法拆分为几个部分,能够放置在不一样类中的不一样位置。

收益

  • 减小重复代码(若是数据处理的代码放在中心位置)。
  • 更好的代码组织性(处理数据的函数靠近实际数据)。

什么时候忽略

  • 有时,行为被有意地与保存数据的类分开。这一般的优势是可以动态地改变行为(见策略设计模式,访问者设计模式和其余模式)。

重构方法说明

搬移函数(Move Method)

问题

你的程序中,有个函数与其所驻类以外的另外一个类进行更多交流:调用后者,或被后者调用。

解决

在该函数最常引用的类中创建一个有着相似行为的新函数。将旧函数变成一个单纯的委托函数,或是旧函数彻底移除。

提炼函数(Extract Method)

问题

你有一段代码能够组织在一块儿。

void printOwing() {
  printBanner();

  //print details
  System.out.println("name: " + name);
  System.out.println("amount: " + getOutstanding());
}

解决

移动这段代码到一个新的函数中,使用函数的调用来替代老代码。

void printOwing() {
  printBanner();
  printDetails(getOutstanding());
}

void printDetails(double outstanding) {
  System.out.println("name: " + name);
  System.out.println("amount: " + outstanding);
}

狎昵关系

狎昵关系(Inappropriate Intimacy)

一个类大量使用另外一个类的内部字段和方法。

问题缘由

类和类之间应该尽可能少的感知彼此(减小耦合)。这样的类更容易维护和复用。

解决方法

  • 最简单的解决方法是运用 搬移函数(Move Method) 和 搬移字段(Move Field) 来让类之间斩断羁绊。

 

  • 你也能够看看是否能运用 将双向关联改成单向关联(Change Bidirectional Association to Unidirectional) 让其中一个类对另外一个说分手。

  • 若是这两个类实在是情比金坚,难分难舍,能够运用 提炼类(Extract Class) 把两者共同点提炼到一个新类中,让它们产生爱的结晶。或者,能够尝试运用 隐藏委托关系(Hide Delegate) 让另外一个类来为它们牵线搭桥。

  • 继承每每形成类之间过度紧密,由于子类对超类的了解老是超事后者的主观愿望,若是你以为该让这个子类本身闯荡,请运用 以委托取代继承(Replace Inheritance with Delegation) 来让超类和子类分家。

收益

  • 提升代码组织性。
  • 提升代码复用性。

重构方法说明

搬移函数(Move Method)

问题

你的程序中,有个函数与其所驻类以外的另外一个类进行更多交流:调用后者,或被后者调用。

解决

在该函数最常引用的类中创建一个有着相似行为的新函数。将旧函数变成一个单纯的委托函数,或是旧函数彻底移除。

搬移字段(Move Field)

问题

在你的程序中,某个字段被其所驻类以外的另外一个类更多地用到。

解决

在目标类新建一个字段,修改源字段的全部用户,令他们改用新字段。

将双向关联改成单向关联(Change Bidirectional Association to Unidirectional)

问题

两个类之间有双向关联,但其中一个类现在再也不须要另外一个类的特性。

解决

去除没必要要的关联。

提炼类(Extract Class)

问题

某个类作了不止一件事。

解决

创建一个新类,将相关的字段和函数从旧类搬移到新类。

隐藏委托关系(Hide Delegate)

问题

客户经过一个委托类来调用另外一个对象。

解决

在服务类上创建客户所需的全部函数,用以隐藏委托关系。

以委托取代继承(Replace Inheritance with Delegation)

问题

某个子类只使用超类接口中的一部分,或是根本不须要继承而来的数据。

解决

在子类中新建一个字段用以保存超类;调整子类函数,令它改而委托超类;而后去掉二者之间的继承关系。

过分耦合的消息链

过分耦合的消息链(Message Chains)

消息链的形式相似于:obj.getA().getB().getC()

问题缘由

若是你看到用户向一个对象请求另外一个对象,而后再向后者请求另外一个对象,而后再请求另外一个对象……这就是消息链。实际代码中你看到的多是一长串 getThis()或一长串临时变量。采起这种方式,意味客户代码将与查找过程当中的导航紧密耦合。一旦对象间关系发生任何变化,客户端就不得不作出相应的修改。

解决方法

  • 能够运用 隐藏委托关系(Hide Delegate) 删除一个消息链。

  • 有时更好的选择是:先观察消息链最终获得的对象是用来干什么的。看看可否以 提炼函数(Extract Method)把使用该对象的代码提炼到一个独立函数中,再运用 搬移函数(Move Method) 把这个函数推入消息链。

收益

  • 能减小链中类之间的依赖。
  • 能减小代码量。

什么时候忽略

  • 过于侵略性的委托可能会使程序员难以理解功能是如何触发的。

重构方法说明

隐藏委托关系(Hide Delegate)

问题

客户经过一个委托类来调用另外一个对象。

 

解决

在服务类上创建客户所需的全部函数,用以隐藏委托关系。

提炼函数(Extract Method)

问题

你有一段代码能够组织在一块儿。

void printOwing() {
  printBanner();

  //print details
  System.out.println("name: " + name);
  System.out.println("amount: " + getOutstanding());
}

解决

移动这段代码到一个新的函数中,使用函数的调用来替代老代码。

void printOwing() {
  printBanner();
  printDetails(getOutstanding());
}

void printDetails(double outstanding) {
  System.out.println("name: " + name);
  System.out.println("amount: " + outstanding);
}

搬移函数(Move Method)

问题

你的程序中,有个函数与其所驻类以外的另外一个类进行更多交流:调用后者,或被后者调用。

解决

在该函数最常引用的类中创建一个有着相似行为的新函数。将旧函数变成一个单纯的委托函数,或是旧函数彻底移除。

相关文章
相关标签/搜索