(七)用组合连接书架与存储器
1. 先把保存动作交给另一个对象
书架负责加入书名,保存方式则可能改变。先用一个保存书名列表的内存存储器,把两个职责接起来:
# 存储器保存一份列表副本;书架通过持有的 store 调用保存动作。
class MemoryStore:
def __init__(self):
self._titles = []
def load(self):
return self._titles.copy()
def save(self, titles):
self._titles = titles.copy()
class BookShelf:
def __init__(self, store):
self._store = store
self._titles = store.load()
def add(self, title):
if title not in self._titles:
self._titles.append(title)
def save(self):
self._store.save(self._titles)
store = MemoryStore()
first = BookShelf(store)
first.add("Python")
print(store.load())
first.save()
second = BookShelf(store)
print(store.load(), second._titles)输出 [] 与 ['Python'] ['Python']。加入只更新第一份书架中的列表;执行 save() 后,存储器才接收快照,第二份书架随后从同一个存储器载入它。
这种把其他对象作为属性、通过它们完成部分工作的安排称为组合。这里 BookShelf 持有存储器引用,两者各自保存状态;外面的 store 也仍然指向同一个存储器。示例最后读取 _titles 是为了观察副本,完整程序会通过公开的读取方法交回记录。
2. 为替换保存方式保留调用接口
书架调用的是 store.load() 与 store.save(...),没有把存储器的内部列表复制到自己的实现代码里。只要另一种存储器也提供这些动作,书架便能沿同一个调用过程工作。后面综合示例会真正换成字典形式的存储器。
到这里,两个类之间的关系是“书架使用存储器”。接下来再处理另一种关系:电子书也是书籍,具有共同的字段与操作,还需要增加下载文件等行为。