读书笔记-重构: 章8 重新组织数据
- 读书笔记-重构: 章8 重新组织数据
- 章8: 重新组织数据
- 8.1 Self Encapsulate Field 自封装字段
- 8.2 Replace Data Value with Object 以对象取代数据值
- 8.3 Change Value to Reference 将值对象改为饮用对象
- 8.4 Change Reference to Value 将引用对象改为值对象
- 8.5 Replace Array with Object 以对象取代数组
- 8.6 Duplicate Observed Data 复制"被监视数据"
- 8.7 Change Unidirectional Association to Bidirectional 将单向关联改为双向关联
- 8.8 Change Bidirectional Association to Unidirectional 将双向关联改为单向关联
- 8.9 Replace Magic Number with Symbolic Constant 以字面常量取代魔法数
- 8.10 Encapsulate Field 封装字段
- 8.11 Encapsulate Collection 封装集合
- 8.12 Replace Record with Data Class 以数据类取代记录
- 8.13 Replace Type Code with Class 以类取代类型码
- 8.14 Replace Type Code with Subclasses 以子类取代类型码
- 8.15 Replace Type Code with State/Strategy 以Stat/Strategy取代类型码
- 8.16 Replace Subclass with Fields 以字段取代子类
- 章8: 重新组织数据
重构的读书笔记, 简单转成python版本的code, 供参考
章8: 重新组织数据
8.1 Self Encapsulate Field 自封装字段
你直接访问一个字段, 但字段间的耦合关系逐渐变额笨拙. 为这个字段建立取值/设置函数, 并且只以这些函数来访问字段
间接访问的好处是, 可以灵活改变获取数据的途径
class A(object): def include(self, arg): return self.low < arg < self.high
to
class A(object): def include(self, arg): return self.low < arg < self.high @property def low(self): return self._low @property def height(self): return self._high
8.2 Replace Data Value with Object 以对象取代数据值
你有一个数据项, 需要与其他数据和行为一起使用才有意义
独立成对象
class Customer(object): def__init__(self, name, area_code, number): .... def get_phone_number(self): return "%s-%s" % (self.area_code, self.number)
to
class Phone(object): def __init__(self, area_code ,number): .... @property def number(self): return "%s-%s" % (self.area_code, self.number) class Customer(object): def__init__(self, name, area_code, number): ....
8.3 Change Value to Reference 将值对象改为饮用对象
你从一个类衍生出许多彼此相等的实例, 希望将他们替换为同一个对象. 将这个值对象变成引用对象
# only 4 types, but 10000 A instance class A(object): def __init__(self, type_id, type_name): self.type_id = type_id self.type_name = type_name
to
class Type(object): def __init__(type_id, type_name): self.type_id = type_id self.type_name = type_name class A(object): def __init__(self, _type): self._type = _type
8.4 Change Reference to Value 将引用对象改为值对象
你有一个引用对象, 很小且值不可变, 而且不易管理. 将它变成一个值对象
手法, 将重构目标变成不可变对象. 即, 只有可以变成不可变对象的才能运用这个技巧
class Currency(object): def __init__(self, code): self.code = code
to
class Currency(object): def __init__(self, code): self._code = code @property def code(self): return self._code def __eq__(self, other): return self.code == other.code
8.5 Replace Array with Object 以对象取代数组
你有一个数组, 其中元素各自代表不同的东西. 以对象替换数组, 对于数组中的每个元素, 以一个字段来表示
row = ["Liverpoo", 15]
to
claas Record(object): def __init__(self, name, wins): self.name = name self.wins = wins record = Record("Liverpoo", 15)
8.6 Duplicate Observed Data 复制"被监视数据"
你有一些领域数据置身于 GUI 控件中, 而领域函数需要访问这些数据. 将数据复制到一个领域对象中. 建立Observer模式, 用以同步领域对象和GUI对象内的重复数据
observer模式, 不解释
8.7 Change Unidirectional Association to Bidirectional 将单向关联改为双向关联
两个类都需要使用对方特性, 但其间只有一条单向连接. 添加一个反向指针, 并使修改函数能够同时更新到两条连接
class Customer(object): def get_orders(self): # need a lot of codes here class Order(object): def __init__(self): pass @property def customer(self): return self._customer @customer.setter def customer(self, customer): self._customer = customer def get_customer_address(): return self._customer.address
to
class Customer(object): def __init__(self): self.orders = [] def add_order(self, order): self.orders.append(order) def get_orders(self): return self.orders class Order(object): def __init__(self): pass @property def customer(self): return self._customer @customer.setter def customer(self, customer): self._customer = customer self._customer.add_order(self) def get_customer_address(): return self._customer.address
8.8 Change Bidirectional Association to Unidirectional 将双向关联改为单向关联
两个类之间有双向关联, 但其中一个类如今不再需要另一个类的特性了
上面的例子, 如果Customer
不再需要get_orders
. 则可以去掉双向连接, 防止僵尸对象出现
8.9 Replace Magic Number with Symbolic Constant 以字面常量取代魔法数
你有一个字面数值, 带有特别含义. 创建一个常量, 根据其意义为它命名, 并将上述字面数值替换为这个常量
def potential_energy(mass, height): return mass * 9.81 * height
to
GRAVITATIONAL_CONSTANT = 9.81 def potential_energy(mass, height): return mass * GRAVITATIONAL_CONSTANT * height
8.10 Encapsulate Field 封装字段
你的类中存在一个public字段, 将它声明为private, 并提供相应访问函数
class A(object): def __init__(self, value): self.value = value
to
class A(object): def __init__(self, value): self.__value = value @property def value(self): return self.__value @value.setter def value(self, v): self.__value = v
8.11 Encapsulate Collection 封装集合
有个函数返回一个集合. 让这个函数返回该集合的一个只读副本, 并在这个类中提供添加/移除集合元素的函数
class A(object): def __init__(self): self._members = [] def get_members(self): return self._members
to
class A(object): def __init__(self): self._members = [] def get_members(): return tuple(self._members) def add_member(self, member): self.members.append(member) def remove_member(self, member): self.members.remove(member)
8.12 Replace Record with Data Class 以数据类取代记录
你需要面对传统编程环境中的记录结构. 为该记录创建一个"哑"数据对象
可能面对的是一个遗留程序, 需要与其记录进行结构交流. 例如从数据库读出来的记录, 接口调用返回数据等
8.13 Replace Type Code with Class 以类取代类型码
类之中有一个类型码, 但它并不影响类的行为. 以一个新的类替换该数值类型码
class Person(object): def __init__(self): self.O = 0 self.A = 1 self.B = 2 slef.AB = 3
to
class Person(object): def __init__(self): self.O = BloodGroup.O self.A = BloodGroup.A self.B = BloodGroup.B slef.AB = BloodGroup.AB
8.14 Replace Type Code with Subclasses 以子类取代类型码
你有一个不可变的类型码, 它会影响到类行为. 以子类取代类型码
使用多态来处理, 需要在一个类中使用if-else
或者switch
来根据类型码做出不同行为的类
class Employee(object): def __init__(self): self.ENGINEER = 1 self.SALESMAN = 0
to
class Employee(object): def __init__(self): class Engineer(Employee): pass class Salesman(Employee): pass
8.15 Replace Type Code with State/Strategy 以Stat/Strategy取代类型码
你有一个类型码, 它会影响类的行为, 但你无法通过继承手法消除它. 以状态对象取代类型码
State模式和Strategy模式
8.16 Replace Subclass with Fields 以字段取代子类
你的各个子类的唯一差别只在"返回常量数据"的函数上. 修改这些函数, 使它们返回超类中的某个(新增)字段, 然后销毁子类
class Person(object): def is_male(self): pass def get_code(self): pass class Male(Person): def is_male(self): return True def get_code(self): return "M" class Feale(Person): def is_male(self): return False def get_code(self): return "F"
to
class Person(object): def is_male(self): return self._is_male def get_code(self): return 'M' if self._is_male else "F"