我正在寻求有关我的代码设计的建议。
介绍
我有几个类,每个类代表一种文件类型,例如:MediaImageFile、MediaAudioFile 和通用(也是基类)MediaGenericFile。
每个文件都有两个变体:Master 和 Version,所以我创建了这些类来定义它们的特定行为。编辑:版本代表主文件的调整大小/裁剪/修剪/等变体。它主要用于预览。
编辑: 为什么我想动态地做它的原因是这个应用程序应该是可重用的(它是 Django 应用程序),因此它应该很容易实现其他 MediaGenericFile 子类而无需修改原始代码。
我想做的事
首先,用户应该能够在不影响原始代码的情况下注册自己的 MediaGenericFile 子类。
文件是版本还是主文件很容易(一个正则表达式)从文件名中识别出来。
/path/to/master.jpg -- master /path/to/.versions/master_version.jpg -- version
Master/Version 类使用 MediaGenericFile 的一些方法/属性,例如文件名(您需要知道文件名才能生成新版本)。
MediaGenericFile 扩展了 LazyFile,它只是一个惰性 File 对象。
现在我需要把它放在一起……</p>
二手设计
在开始编写“版本”功能之前,我有工厂类 MediaFile,它根据扩展名返回适当的文件类型类:
>>> MediaFile('path/to/image.jpg')
<<< <MediaImageFile 'path/to/image.jpg'>
Master 和 Version 类定义了使用 MediaGenericFile 等的方法和属性的新方法。
方法一
一种方法是动态创建新类型,它继承 Master(或 Version)和 MediaGenericFile(或子类)。
class MediaFile(object):
def __new__(cls, *args, **kwargs):
... # decision about klass
if version:
bases = (Version, klass)
class_name = '{0}Version'.format(klass.__name__)
else:
bases = (Master, klass)
class_name = '{0}Master'.format(klass.__name__)
new_class = type(class_name, bases, {})
...
return new_class(*args, **kwargs)
方法二
第二种方法是在 Master/Version 中创建方法“contribute_to_instance”并在创建 new_class 后调用它,但这比我想象的要棘手:
classs Master(object):
@classmethod
def contribute_to_instance(cls, instance):
methods = (...)
for m in methods:
setattr(instance, m, types.MethodType(getattr(cls, m), instance))
class MediaFile(object):
def __new__(*args, **kwargs):
... # decision about new_class
obj = new_class(*args, **kwargs)
if version:
version_class = Version
else:
version_class = Master
version_class.contribute_to_instance(obj)
...
return obj
但是,这不起作用。调用 Master/Version 的方法仍然存在问题。
问题
实现这种多重继承的好方法是什么?
这个问题怎么称呼?:) 我试图找到一些解决方案,但我根本不知道如何命名这个问题。
提前致谢!
答案注释
拉尔斯曼斯
对于我的情况,比较和实例检查不会有问题,因为:
无论如何都要重新定义比较
class MediaGenericFile(object): def __eq__(self, other): return self.name == other.name
我从不需要检查 isinstance(MediaGenericFileVersion, instance)。我正在使用 isinstance(MediaGenericFile, instance) 和 isinstance(Version, instance) 两者都按预期工作。
然而,在我看来,为每个实例创建新类型听起来是相当大的缺陷。
好吧,我可以在元类中动态创建这两种变体,然后使用它们,例如:
>>> MediaGenericFile.version_class
<<< <class MediaGenericFileVersion>
>>> MediaGenericFile.master_class
<<< <class MediaGenericFileMaster>
进而:
class MediaFile(object):
def __new__(cls, *args, **kwargs):
... # decision about klass
if version:
attr_name = 'version_class'
else:
attr_name = 'master_class'
new_class = getattr(klass, attr_name)
...
return new_class(*args, **kwargs)
最终解决方案
最后设计模式是工厂类。MediaGenericFile 子类是静态类型的,用户可以自己实现和注册。Master/Version 变体在元类中动态创建(从几个 mixin 粘合在一起)并存储在“缓存”中,以避免 larsmans提到的危险。
感谢大家的建议。最后我理解了元类的概念。好吧,至少我认为我理解它。推送源主...</p>