首页 > 解决方案 > mixins 是跨不同实体类型存储多个属性的正确选择吗?

问题描述

我目前正在构建一个系统,该系统将跨多个来源聚合帖子。这些来源几乎没有共同的属性——例如,所有来源的唯一共同点是帖子包含文本:

class Post:
    def __init__(self, text=None):
        self.text = text

    def persist(self):
        row_id = FoobarDB.insert('post', text=self.text).row_id
        id = row_id
        for superclass in type(self).mro():
            try:
                super(superclass, self).persist(id)
            except AttributeError: pass
        return id

    @classmethod
    def load(cls, id):
        post_text = FoobarDB.select('post', row_id=id).text
        post = cls(post_text)
        for superclass in cls.mro():
            try:
                super(superclass, post).load(id)
            except AttributeError: pass
        return post

不同的来源有不同的特征:一些有标签,一些有标题,一些有赞成票和反对票,等等。我正在考虑使用 mixins 来表示所有这些,所以Post专门用于不同来源的子类将继承Post自所有适用于该来源的 mixin:

class TwitterPost(Post, HasAuthor, HasScore): ...
class StackExchangePost(Post, HasAuthor, HasScore, HasTitle, HasTags, HasComments): ...
class XkcdPost(Post, HasTitle, HasImage): ...
class RedditPost(Post, HasTitle, HasScore, HasImage, HasComments): ...

这种方法的问题在于,我最终会得到许多重复的 mixin 声明,据我所知,如果没有技巧,这些声明是无法优化的eval

class HasAuthor:
    @property
    def author(self):
        try: return self._author
        except AttributeError: return None

    @author.setter
    def set_author(self, value): self._author = value

    def persist(self, id):
        FoobarDB.insert('author', post_id=id, author=self.author)

    def load(self, id):
        self.author = FoobarDB.select('author', post_id=id).author

class HasImage:
    @property
    def image_url(self):
        try: return self._image_url
        except AttributeError: return None

    @image_url.setter
    def set_image(self, value): self._image_url = value

    def persist(self, id):
        FoobarDB.insert('image', post_id=id, image_url=self.image_url)

    def load(self, id):
        self.image_url = FoobarDB.select('image', post_id=id).image_url

这段代码重复向我表明,mixin 在这里不是正确的选择,或者至少不应该以这种方式使用它们。有没有更好的方法来表示具有一些共同属性但许多属性不同的多个类?

另一个限制是我不知道不同的帖子有什么属性。我需要能够添加新的属性类型以适应新的帖子类型,而不必在基Post类中更改太多代码。(事实上​​,我认为这种方法可行的原因之一是,Post如果数据后端是关系数据库,它会自动将实体拆分为跨不同表的许多行。)

标签: pythonpropertiesdata-modelingmixins

解决方案


推荐阅读