Python 用于初始化父类或子类对象的对象工厂设计
我正在构建一个将目录作为输入并在必要时执行操作的工具。这些操作因某些变量而异,因此我创建了一些类对象,它们以有组织的方式帮助我满足需求 然而,我遇到了一个难题:如何最好地设计以下场景 为了简单起见,假设只有目录(没有文件)。此外,下面是一个高度简化的示例 我有以下父类:Python 用于初始化父类或子类对象的对象工厂设计,python,python-3.x,oop,inheritance,Python,Python 3.x,Oop,Inheritance,我正在构建一个将目录作为输入并在必要时执行操作的工具。这些操作因某些变量而异,因此我创建了一些类对象,它们以有组织的方式帮助我满足需求 然而,我遇到了一个难题:如何最好地设计以下场景 为了简单起见,假设只有目录(没有文件)。此外,下面是一个高度简化的示例 我有以下父类: #directory.py 从pathlib导入路径 类目录: 定义初始路径(自、绝对路径): self.path=路径(绝对路径) def内容(自我): 返回[self.path.iterdir()中c的目录(c)] 因此,
#directory.py
从pathlib导入路径
类目录:
定义初始路径(自、绝对路径):
self.path=路径(绝对路径)
def内容(自我):
返回[self.path.iterdir()中c的目录(c)]
因此,我在父类中有一个方法,它为绝对路径中的初始目录中的每个目录返回目录
实例
上面所做的是保存所有目录上可以执行的所有方法。现在,我有一个单独的类,它继承了上面的内容并添加了更多的方法
#特殊目录.py
从目录导入目录
类专用目录(目录):
定义初始路径(自、绝对路径):
super().\uuuu init\uuuu(绝对路径)
#更多方法
我正在使用类似对象工厂的方法,根据如下条件构建一个或另一个:
#目录_factory.py
从目录导入目录
从特殊目录导入特殊目录
def拾取(路径):
如果path else目录(path)中的“foo”,则返回SpecialDirectory(path)
因此,如果路径中存在'foo'
,它应该是一个特殊目录
,而不是允许它做目录
所做的一切
我面临的问题是content()
方法。两者都应该能够做到这一点,但我不希望它局限于制作目录
实例的列表。如果其任何内容包含“foo*”
,则应为专用目录
Directory
不(也不应该)知道SpecialDirectory
,因此我尝试导入并使用工厂,但它抱怨一些循环导入(这很有意义)
我并没有特别陷入困境,因为我已经想出了一个临时解决方案,但它并不漂亮。因此,我希望我能得到一些技巧,知道对于这种特定情况,什么样的解决方案才是有效和干净的。您需要的有时被称为“虚拟构造函数”,这是一种允许子类在调用基类构造函数时确定创建的类实例类型的方法。在Python中没有这样的东西(或者C++),但是你可以模拟它们。下面是一个这样做的例子
请注意,此代码与标题为的问题(其中包含有关该技术的更多信息)中的代码非常相似。也可以看到
哦,这看起来很有趣。我要做进一步的阅读。在我的研究中,我发现了\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu新的
方法,但不是子。我不再深入研究这个问题,因为似乎有些人不同意让类构造函数返回不同类型的实例(在本例中是一个孩子)。这个问题可能是出于同样的原因提出的(我在回答中提到了我不同意)。虚拟构造器的概念已经存在了很长一段时间,所以你也应该对它进行研究(因为这就是它——它是对象工厂设计模式的另一个名称)。我想到了使用\uuuu init\u subclass\uuu()
注册提案中某一部分的子类,该部分是在Python 3.6中实现的。太棒了,谢谢您提供的所有信息!这很有教育意义!只要一个问题,如果你不介意我问你将来的参考。如果碰巧我知道只有一个子类,你有什么理由不建议跳过整个子类
malarky,并在\uuuu new\uuuu
方法中通过执行If SpecialDirectory.pick(path):
直接进行比较?编辑我发布的评论后,你扔了最后一条评论,这几乎回应了这个哈哈。再次感谢!这样做的缺点是它违反了封装,意味着基类知道它的子类。如果要这样做,不妨创建一个了解所有子类的工厂函数。要点是关于添加额外子类而不需要修改基类(或单独的工厂函数)的能力。
from pathlib import Path
class Directory:
subclasses = []
@classmethod
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
cls.subclasses.append(cls)
def __init__(self, absolute_path):
self.path = Path(absolute_path)
def __new__(cls, path):
""" Create instance of appropriate subclass. """
for subclass in cls.subclasses:
if subclass.pick(path):
return object.__new__(subclass)
else:
return object.__new__(cls) # Default is this base class.
def content(self):
return [Directory(c) for c in self.path.iterdir()]
def __repr__(self):
classname = type(self).__name__
return f'{classname}(path={self.path!r})'
# More methods
...
class SpecialDirectory(Directory):
def __init__(self, absolute_path):
super().__init__(absolute_path)
@classmethod
def pick(cls, path):
return 'foo' in str(path)
# More methods
...
if __name__ == '__main__':
root = './_obj_factory_test'
d = Directory(root)
print(d.content())