前言:
尽量采用 合成 / 聚合 的方式实现复用,尽量在代码中少使用继承。组合 / 聚合 复用就是在一个新对象中使用一些已有的对象,使这些已有对象成为新对象的一部分,从而达到复用已有功能的目的。
聚合
聚合用来表示“拥有”,关系或者整体与部分的关系。代表部分的对象可能存在被多个代表整体的对象所共享。不一定因某个代表整体的对象消亡而消亡,其生命周期可以是超越整体的。例如班级和学生,即便班级被删除,但学生还能存在,因为学生仍可以被培训机构引用。表示聚合关系的 UML 图如下:
modb_20211009_382f8e5a-2858-11ec-abb4-fa163eb4f6be.jpg
class Student:
pass
class ClassRoom:
def __init__(self, studnet):
self.student = student
if __name__ == "__main__":
s = Student()
c = ClassRoom(s)
通过上述代码我们可以发现,基表 ClassRoom 类的实例被销毁了,但是学生实例任然存在。
合成
合成用来表示一种更强的“拥有”关系,在一个合成关系中,部分和整体的生命周期是一致的,一个合成的新对象完全拥有对其组成部分的支配权,如创建和销毁等。也就是说合成的新对象对其组成部分的内存分配,内存释放有绝对的责任。一个合成关系中成分对象是不能与另一个合成关系共享的,一个成分对象在同一个时间内只能属于一个合成关系。例如房子与房间的关系,当房子被拆除了,自然房间就不复存在了。
modb_20211009_38a2a5a2-2858-11ec-abb4-fa163eb4f6be.jpg
class Room:
def createRoom(self):
print("创建了一个房间")
class House:
def __init__(self):
self.room = Room()
def createHouse(self):
self.room.createRoom()
if __name__ == "__main__":
h = House()
h.createHouse()
通过上述代码我们可以发现,房间 Room 会随着House 类实例的消亡而消亡。
组合 或 继承的判定条件
“Has-A” 和 “Is-A” ?
满足 "Is-A" 的关系才能继承,组合是 "Has-A" 的关系;Is-A顾名思义就是“是一个” 的意思,表示一个类是另一个类的一种;Has-A 是“有一个”的意思,表示一个类是另一个类的一部分。请看如下 UML 图:
modb_20211009_393acdf0-2858-11ec-abb4-fa163eb4f6be.jpg
父类 “人” 被继承到 “学生”,“经理”和“雇员”等子类,但实际上“学生”,“经理”,“雇员”分别描述的是一种角色,而“人”是可以同时分饰不同的角色。比如一个人虽然是“经理”,但是在老板眼里他却和普通的“雇员”没差别,而“人”同时还可以参加MBA课程,所以他也是一个“学生”。若使用继承来实现角色,假设 Python 和 Java 一样不支持多重继承,这会使一个“人”在成为“雇员”之后,就永远为“雇员”,不能在成为“学生”或“经理”,而这显然是不合理的。实例代码如下:
from abc import ABCMeta, abstractmethod
class Person:
__metaclass__ = ABCMeta
@abstractmethod
def show(self):
pass
class staff(Person):
def show(self):
print("i am a staff")
class student(Person):
def show(self):
print("i am a student")
class manager(Person):
def show(self):
print("i am a manager")
if __name__ == "__main__":
p = staff()
p.show()
以上代码逻辑的错误原因是把角色的等级结构和人的等级结构混淆了,错误的把 Has-A 关系认为是 Is-A 关系,更正后的 UML图如下:
modb_20211009_39bcb77a-2858-11ec-abb4-fa163eb4f6be.jpg
遵循了 合成 / 聚合 复用原则的示例代码:
from abc import ABCMeta, abstractmethond
class Role:
__metaclass__ = ABCMeta
@absstractmethod
def show(self):
pass
class staff(Role):
def show(self):
print("i am a staff")
class student(Role):
def show(self):
print("i am a student")
class manager(Role):
def show(self):
print("i am a manager")
class Person:
def set_role(self, role):
self.role = role
def get_role(self):
return self.role.show()
if __name__ == "__main__":
p = Person()
p.set_role(student())
p.get_role()
p.set_role(mananger())
p.get_role()
网友评论