python - 可以用 Python 实现关联类吗?
问题描述
我刚刚开始学习软件开发,并且正在用 UML 类图对我的系统进行建模。我不确定如何在代码中实现这一点。
为了简单起见,我们假设以下示例:有一个 Room 和一个 Guest 类,关联 Room(0.. )-Guest(0.. ) 和一个关联类 RoomBooking,其中包含预订详细信息。如果我的系统想要查看特定客人的所有房间预订,我将如何在 Python 中对此进行建模?
解决方案
从 UML 设计开发的大多数 Python 应用程序都由关系数据库支持,通常通过 ORM。在这种情况下,您的设计非常简单:您RoomBooking
是数据库中的一个表,而查找RoomBooking
给定所有对象的Guest
方式只是一个 ORM 查询。保持模糊而不是使用特定的 ORM 语法,如下所示:
bookings = RoomBooking.select(Guest=guest)
使用 RDBMS 但没有 ORM,它并没有太大的不同。像这样的东西:
sql = 'SELECT Room, Guest, Charge, Paid FROM RoomBooking WHERE Guest = ?'
cur = db.execute(sql, (guest.id))
bookings = [RoomBooking(*row) for row in cur]
这表明如果您不使用 RDBMS,您会做什么:任何将存储为具有外键的表的关系都将作为某种 dict 存储在内存中。
例如,您可能有一个将客人映射到房间预订集的字典:
bookings = guest_booking[guest]
或者,如果您没有大量酒店,您可能会隐式使用此映射,每个酒店都有客人到预订的一对一映射:
bookings = [hotel.bookings[guest] for hotel in hotels]
由于您从 UML 开始,您可能在考虑严格的 OO 术语,因此您需要将此 dict 封装在某个类中,在一些 mutator 和 accessor 方法后面,这样您可以确保您不会意外中断任何不变量。
有几个明显的地方可以放置它——一个BookingManager
对象对于客人到预订集的映射是有意义的,而且它Hotel
本身对于每家酒店的客人到预订来说是如此明显的地方,以至于我使用了它不考虑上面。
但是另一个更接近ORM设计的地方是在RoomBooking
类型上的一个类属性中,由类方法访问。如果您以后需要,这也允许您扩展事物,例如,按酒店查找事物 - 然后您将两个 dicts 作为类属性,并确保单个方法始终更新它们,所以您知道它们是始终一致。
那么,让我们看一下:
class RoomBooking
guest_mapping = collections.defaultdict(set)
hotel_mapping = collections.defaultdict(set)
def __init__(self, guest, room):
self.guest, self.room = guest, room
@classmethod
def find_by_guest(cls, guest):
return cls.guest_mapping[guest]
@classmethod
def find_by_hotel(cls, hotel):
return cls.hotel_mapping[hotel]
@classmethod
def add_booking(cls, guest, room):
booking = cls(guest, room)
cls.guest_mapping[guest].add(booking)
cls.hotel_mapping[room.hotel].add(booking)
当然,您的Hotel
实例可能还需要添加预订,因此如果两个不同的预订在重叠日期覆盖同一个房间,它可能会引发异常,无论这种情况发生在RoomBooking.add_booking
,还是在调用两者的更高级别的函数中Hotel.add_booking
和RoomBooking.add_booking
。
如果这是多线程的(这似乎是一个很好的可能性,因为您正朝着受 Java 启发的设计路径走这么远),您将需要一个大锁或一系列细粒度的锁整个交易。
对于持久性,您可能希望将这些映射与公共对象一起存储。但是对于足够小的数据集,或者对于很少重新启动的服务器,只保留公共对象并在加载时重建映射可能更简单,方法是在加载过程中执行一堆add_booking
调用。
如果你想让它更像 ORM 风格,你可以有一个find
方法,它接受关键字参数并以一种简单的方式手动执行“查询计划”:
@classmethod
def find(cls, guest=None, hotel=None):
if guest is None and hotel is None:
return {booking for bookings in cls.guest_mapping.values()
for booking in bookings}
elif hotel is None:
return cls.guest_mapping[guest]
elif guest is None:
return cls.hotel_mapping[hotel]
else:
return {booking for booking in cls.guest_mapping[guest]
if booking.room.hotel == hotel}
但这已经把事情推到了一个地步,你可能想回去问问你一开始不使用 ORM 是否正确。如果这对于您的简单玩具应用程序来说听起来非常繁重,请查看sqlite3
数据库(Python 附带,使用它比想出一种方法pickle
或json
所有数据进行持久化所需的工作更少)和SqlAlchemy
ORM . 没有太多的学习曲线,也没有太多的运行时开销或编码时间样板。
推荐阅读
- kotlin - Kotlin - UI 更新之间的延迟
- javascript - JavaScript:在 Promise 中使用 Async/Await
- python - Python将字符串中的UTC日期时间转换为unix时间
- javascript - JavaScript 在浏览器中提取 zip 文件并呈现为文件系统
- oracle - 从 sqlcl 运行 liquibase 更新时找不到 SQL 文件
- javascript - 如何找到一个与另一个值异或的值?
- java - 总和为给定数字的子集计数(允许重复)。没有得到正确的输出
- iis - IIS 10 中的重定向问题
- string - 如何将 AnsiStr 转换为字节,反之亦然?
- c# - 如何在本地测试/运行 azure times 功能