读书笔记-重构: 章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"