第八章 重新组织数据

Self Encapsulate Field (自封装字段)

  • 现象:你直接访问一个字段,但与字段之间的耦合逐渐变得笨拙
  • 做法:为这个字段建立取值/设值函数,并且只以这些函数来访问字段
  • 好处:
    • 子类可以通过覆写一个函数而改变获取数据的途径;
    • 支持更灵活的数据管理方式;

Replace Data Value with Object (以对象取代数据值)

  • 现象:你有一个数据项,需要与其他数据和行为一起使用才有意义
  • 做法:将数据项变成对象
  • 值对象,意味着 new 一个对象

Change Value to Reference (将值对象改为引用对象)

  • 现象:你从一个类衍生出许多彼此相等的实例,希望将它们替换为同一个对象
  • 做法:将这个值对象变成引用对象
  • 预先创建好的对象放入表中,通过工厂函数(create),查表获取
  • 使用工厂函数时,一般构造函数声明为private
class Order {
	public Order (String customer) {
		_customer = Customer.create(customer);
	}
	private Customer _customer;
};

class Customer {
	public static Customer create(String name) {
		//return new Customer(name);
		return (Customer) _instances.get(name);
	}
	private Customer(String name) {
		_name = name;
	}
	static void loadCustomers() {
		new Customer("Lemon Car Hire").store();
		new Customer("Associated Coffee Machines").store();
		new Customer("xxx").store();
	}
	private void store() {
		_instances.put(this.getName(), this);
	}
	private static Dictionary _instances = new Hashtable();
};

Change Reference to Value (将引用对象改为值对象)

  • 现象:你有一个引用对象,很小且不可变,而且不易管理
  • 做法:将它变为一个值对象

Replace Array with Object (以对象取代数组)

  • 现象:你有一个数组,其中的元素各自代表不同的东西
  • 做法:以对象替换数组,对于数组中的每个元素,以一个字段来表示

Duplicate Observed Data (复制“被监视数据”)

  • 现象:你有一些领域数据置身于GUI控件中,而领域函数需要访问这些数据
  • 做法:将该数据复制到一个领域对象中。建立一个Observer模式,用以同步领域对象和GUI对象内的重复数据。
  • 一个分层良好的系统,应该将处理用户界面和处理业务逻辑的代码分开,好处:
    • 可灵活使用不同的用户界面来表现相同的业务逻辑。如果同时承担两种责任,用户界面会变得过分复杂
    • 与GUI隔离之后,领域对象的维护和演化会更容易,可让不同开发者负责不同部分的开发
  • MVC(Model-View-Controller)模式

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

  • 现象:两个类都需要使用对方特性,但其间只有一条单向连接
  • 做法:添加一个反向指针,并使修改函数能够同时更新两条连接
  • 缺点:造成紧耦合

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

  • 现象:两个类之间有双向关联,但其中一个类如今不再需要使用另一个类的特性
  • 做法:去除不必要的关联

Replace Magic Number with Symbolic Constant(以字面常量取代魔法数)

  • 现象:你有一个字面数值,带有特别含义
  • 做法:创造一个常量,根据其意义为它命名,并将上述的字面数值替换为这个常量
  • 魔法数:拥有特殊意义,却又不能明确表现出这种意义的数字。

Encapsulate Field(封装字段)

  • 现象:你的类存在一个public字段
  • 做法:将它声明为private,并提供相应的访问函数
  • 面向对象的首要原则之一就是封装,或者称为“数据隐藏”。
  • 尝试将使用访问函数的代码,移到访问函数所在的类中

Enapsulate Collection(封装集合)

  • 现象:有个函数返回一个集合
  • 做法:让这个函数返回该集合的一个只读副本,并在这个类中提供添加、移除集合元素的函数。
  • 取值函数不该返回集合自身,这会让用户能够修改集合内容而集合拥有者却一无所悉,也会对用户暴露过多对象内部数据结构的信息。
  • 提供添加、删除集合元素的函数。

Replace Record with Data Class(以数据类取代记录)

  • 现象:你需要面对传统编程环境中的记录结构
  • 做法:为该记录创建一个“哑”数据对象
    • 新建一个类,表示这个记录
    • 对于记录中的每一项数据,在新建类中建立对应的一个private字段,并提供相应的取值、设置函数

Replace Type Code with Class(以类取代类型码)

  • 现象:类之中有一个数值类型码,但它并不影响类的行为,只是对象的一个属性
  • 做法:以一个新类替换该数值类型码
  • 以便编译器可以对这个类进行类型检查

Replace Type Code with Subclasses(以子类取代类型码)

  • 现象:你有一个不可变的类型码,它会影响类的行为
  • 做法:以子类取代这个类型码,借助多态来处理变化行为
  • 标志:像switch这样的条件表达式。switch语句或者if-then-else结构。
  • 为了能够顺利进行多态重构,首先应该将类型码替换为可拥有多态行为的继承体系,这样的一个继承体系应该以类型码的宿主类为基础,并针对每一种类型码各建立一个子类
  • 如果宿主类中并没有出现条件表达式,那么Replace Type Code with Class更合适,风险也比较低

Replace Type Code with State/Strategy

  • 现象:你有一个类型码,它会影响类的行为,但你无法通过继承手法消除它
  • 做法:以状态对象取代类型码,宿主类包含类型对象作为属性
  • 类型码的值在对象生命期中发生变化(工程师升任经理) 或 其他原因使得宿主类不能被继承,可用此重构手法。

Replace Subclass with Fields (以字段取代子类)

  • 现象:你的各个子类的唯一差别只在“返回常量数据”的函数身上
  • 做法:修改这些函数,使他们返回超类中的某个(新增)字段,然后销毁子类
  • 建立子类的目的,是为了增加新特性或变化其特性
  • 常量函数:返回一个硬编码的值。常量函数有其用途,若子类中只有常量函数,实在没有足够的存在价值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值