在 Python 中,如何维护对象之间的关系?考虑以下假想的人员管理系统。假设每个人员对象都属于多个组对象,每个组包含多个人员对象。我们可以通过向每个人员和每个组对象添加一个列表来表示它,但当我们创建、删除或修改对象时,我们必须保持同步。在这种情况下,更改回调不太好用,因为它们可能导致无限循环。
现在假设每个组都有一个名称和一个描述。名称存储在字典中,以便我们可以找到哪个组使用哪个名称,并且对描述进行索引以便我们可以搜索它。每当小组发生变化,都需要更新这些内容。
该应用程序具有可以显示人员和组的 GUI。每当对象的属性发生变化时,GUI 需要更新。
假设我们必须处理大量这样的效果。追踪这一点相当混乱。我可以想象这些使用属性、自定义集合甚至元类。有没有任何设计模式/框架来处理这类系统?
2、解决方案
解决方案一
大多数 ORM 可以处理此问题。只需使用内存中的 SQLite 表,让它来完成艰苦的工作。
解决方案二
这很棘手。是的,人员和组数据可以映射到关系数据库中的表,但自动更新视图更具挑战性。
幸运的是,Qt(因此还有 PyQT)有一个 MVC 框架,可以自动处理您想要的大部分内容。数据存储组件可以使用数据库表来存储人员和组数据。您还可以在同一基础数据模型上创建多个视图,并将它们配置为在基础数据更改时自动更新。这使用了一个称为 Signals 的 Qt 特性,这些视图订阅了模型的 Signals,以便在发生变更时得到通知。
“Using Rapid GUI Programming with Python and QT”一书中有一些与此类似的情况的示例,请参阅第 14 章和第 15 章。也可能还有其他 GUI 框架提供类似的 MVC 功能,其中视图在基础数据发生变化时会自动得到通知。
代码例子
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy import create_engine
Base = declarative_base()
class Person(Base):
__tablename__ = 'person'
id = Column(Integer, primary_key=True)
name = Column(String)
groups = relationship("Group", secondary="person_group")
class Group(Base):
__tablename__ = 'group'
id = Column(Integer, primary_key=True)
name = Column(String)
description = Column(String)
people = relationship("Person", secondary="person_group")
class PersonGroup(Base):
__tablename__ = 'person_group'
person_id = Column(Integer, ForeignKey('person.id'), primary_key=True)
group_id = Column(Integer, ForeignKey('group.id'), primary_key=True)
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
person1 = Person(name='John Smith')
person2 = Person(name='Jane Doe')
group1 = Group(name='Sales', description='The sales department')
group2 = Group(name='Marketing', description='The marketing department')
person1.groups.append(group1)
person1.groups.append(group2)
person2.groups.append(group1)
session.add_all([person1, person2, group1, group2])
session.commit()
for person in session.query(Person).all():
print(person.name)
for group in person.groups:
print("\t", group.name)
输出:
John Smith
Sales
Marketing
Jane Doe
Sales