Self Encapsulate Field(自封装值域)
-
你直接访问一个字段(Field),但与值域之间的耦合关系主键变得笨拙。
-
为这个值域简历get/set函数,并且只以这些函数来访问值域。
- 优点:子类可以通过覆写一个函数而改变获取数据的途径;支撑更灵活的数据管理方式
-
直接访问变量
- 优点:容易阅读
-
对于构造函数,应直接访问值域,要不就建立另一个独立的构造函数,在有subclass时,价值就体现出来了。
Replace Data Value with Object(以对象取代数据值)
- 你有一笔数据项(data item),需要额外的数据和行为。变为组合关系
-
做法:
- 为待替换数值新建一个类,在新类中加入这个字段的取值函数,再加上一个接受此字段为参数的构造函数
- 将源类中的待替换树脂字段的类型改为前面新建的类
- 修改源类中该字段的取值函数,令他调用新类的取值函数
Change Value to Reference(将实值对象改为引用对象)
你有一个class,衍生出许多相等实体,你希望将他们替换成单一对象,组合变关联
Change Reference to Value(将引用对象改为值对象)
- 如果引用对象开始变得难用,可以将它改为值对象
- 检查重构目标是否为不可变对象,或是否可修改为不可变对象,如果不能改为不可变的,则放弃本项重构。
- 使引用对象变得不可更改的简单做法是去掉setXXX()方法
- 重写对象的equals和hashcode方法,使
new XXX().equals(new XXX()) == true;
Replace Array with Object(以对象取代数组)
-
如果数组中的元素代表不同的东西,则将数组替换成对象,按照字段方式方便读取。
-
方式:
- 新建一个类表示数组拥有的所有信息,并在其中以一个public字段保存原先的数组
- 逐一为数组元素添加取值/设值函数
- 当对数组的访问都有访问函数时,将数组改为private
- 当所有元素都有相应字段后,删除该数组
Duplicate Observed Data(复制“被监视数据”)
-
动机:一个良好的系统,应该将处理用户界面和处理业务逻辑的代码分开,
- 你可能需要使用不同的用户界面来表现相同的业务逻辑,如果同时承担两种责任,用户界面会变得过分复杂
- 与GUI隔离之后,领域对象的维护和演化都会更容易,甚至可以让不同的开发者负责不同部分的开发
- 行为可以轻易地划分,但数据往往不能,需要使用多层架构系统来保持他们同步
- Interval为被观察者Observable,继承Observable;Interval Window为观察者Observer,实现Observer接口
Change Unidirectional Association to Bidirectional(将单向关联改为双向关联)
- 两个类都需要使用对方的特性,但其间只有一条单向连接
- 在被引用端增加一个字段,用以保存反向指针Order为引用端,Customer为被引用端
Change Bidirectional Association to Unidirectional(将双向关联改为单向关联)
- 和上面相反
Replace Magic Number with Symbolic Constant(以字面常量取代魔法数)
-
创建一个常量,根据其意义为他命名,并将字面数值替换为这个常量
将
int a = b * c + 10.5;中10.5使用常量表示,如下 :int a = b * c + CONSTANT;static fianl double CONSTANT = 10.5
Encapsulate Field(封装字段)
- 当类中存在一个public字段,将它声明为private,并提供相应的访问函数
Encapsulate Collection(封装集合)
-
让这个函数返回集合的一个只读副本,并在这个类中提供添加/移除集合元素的函数
以下面集合为例
// 保证courses只能通过类方法进行修改,而不能在外部修改
public class Person {
/**
* <对集合进行初始化>
*/
private Set<Course> courses = new HashSet<>();
// get方法返回不可变副本
public Set<Course> getCourses() {
return Collections.unmodifiableSet(courses);
}
// 设置函数已经不再需要,所有对set的操作都可保证不受外部影响
// public void initializeCourses(Set<Course> courses) {
// Iterator iter = courses.iterator();
// courses.addAll(courses);
// }
// 添加元素
public void addCourse(Course course) {
this.courses.add(course);
}
// 移除元素
public void removeCourse(Course course) {
this.courses.remove(course);
}
// 类行为方法
int numberOfAdvancedCourse() {
Iterator<Course> iterator = getCourses().iterator();
int count = 0;
while(iterator.hasNext()) {
Course next = iterator.next();
if (next.isAdvanced()) {
count++;
}
}
return count;
}
}
Replace Record with Data Class(以数据类取代记录)
- 面对传统编程环境中的记录结构,为改记录创建一个“哑”数据对象
- 常用手法:Replace Array with Object
Replace Type Code with Class(以类取代类型码)
Replace Type Code with Subclasses(以子类取代类型码)
- 如果类型码不会影响宿主类的行为,可以使用Replace Type Code with Class处理
- 如果影响宿主类行为,则使用多态来处理行为
- 建立子类后,使用push down method 和 push down field将相关字段和函数推到子类中去
- 将父类的构造函数改为工厂函数
Replace Type Code with State/Strategy(以state/strategy取代类型码)
- 你有一个类型码,它会影响类的行为,但你无法通过继承手法消除它
- 以Emplyee作为源类,将EmployeeType作为变量放入源类中,EmployeeType作为抽象类,抽象类负责创建子类,各类型作为子类继承。
- 使用State/Strategy模式进行构造,这两个模型的整改步骤是相通的。
Replace Subclass with Fields(以字段取代子类)
- 你的各个子类的唯一差别只在“返回常量数据”的函数身上
- 和替换为子类相反,子类中只有常量函数,实在没有足够的存在价值。