组合工厂函数的编程模式
Programming pattern for combining factory functions
假设你有一堆工厂函数,每个函数做两件事:
- 修改或添加参数到 class
的初始化
- 之后对 class 实例做一些事情
例如
class Dog:
def __init__(self, **very_many_kwargs):
pass
def create_police_dog(department, **dog_kwargs):
dog_kwargs['race'] = 'pitbull_terrier'
dog = Dog(**dog_kwargs)
police_academy = PoliceAcademy()
police_academy.train(dog)
return dog
def create_scary_dog(**dog_kwargs):
dog_kwargs['teeth_size'] = 'MAX'
dog_kwargs['eye_color'] = fetch_angry_eye_colors('https://dogs.com')
dog = Dog(**dog_kwargs)
dog.experience_unhappy_childhood()
return dog
如何串联多个这样的函数?
我认为我的解决方案不是最好的,并且对任何其他解决方案都非常感兴趣。但这是我的想法:
class DogFactory:
def __init__(self):
self.dog_kwargs = {}
self.dog_functions = []
def scary(self):
self.dog_kwargs['teeth_size'] = 'MAX'
self.dog_kwargs['eye_color'] = fetch_angry_eye_colors('https://dogs.com')
self.dog_functions.append(Dog.experience_unhappy_childhood)
return self
def police(self):
self.dog_kwargs['race'] = 'pitbull_terrier'
police_academy = PoliceAcademy()
self.dog_functions.append(police_academy.train)
return self
def create(self):
dog = Dog(**self.dog_kwargs)
for f in self.dog_functions:
f(dog)
return dog
dog = DogFactory() \
.scary() \
.police() \
.create()
每个函数都应该接受 Dog
的 现有 实例并修改它,然后 return 修改后的实例。这样,您就可以简单地组合函数。 (这在某种程度上相当于 Builder 模式的功能,尽管下面的示例有些笨拙和笨拙。)
class Dog:
def __init__(self, **very_many_kwargs):
pass
def create_police_dog(dog, department):
dog.race = 'pitbull_terrier'
police_academy = PoliceAcademy()
police_academy.train(dog)
return dog
def create_scary_dog(dog):
dog.teeth_size = 'MAX'
dog.eye_color = fetch_angry_eye_colors('https://dogs.com')
dog.experience_unhappy_childhood()
return dog
scary_police_dog = create_scary_dog(
create_police_dog(
Dog(),
'vice'
)
)
我认为这是构建器模式的一个更典型的实现。
class Dog:
...
class DogBuilder:
def __init__(self):
self.kwargs = {}
self._train = False
self._experience_unhappy_childhood = False
def build(self):
d = Dog(**self.kwargs)
if self._train:
PoliceAcademy().train(d)
if self._experience_unhappy_childhood:
d.experience_unhappy_childhood()
return d
def train(self):
self._train = True
def set_race(self, r):
self.kwargs['race'] = r
def experience_unhappy_childhood(self):
self._experience_unhappy_childhood = True
def make_police_dog(self, department):
self.kwargs['department'] = department
return self.set_race('pitbull_terrier').train()
def make_scary_dog(self):
return self.set_eye_color(fetch_angry_eye_colors('https://dogs.com')).
set_teeth_size('MAX').
experience_unhappy_childhood()
scary_police_dog = (DogBuilder()
.make_police_dog('vice')
.make_scary_dog()
.build()
这是一种使用多重继承的方法(更具体地说,合作多重继承)。
class Dog:
def __init__(self, *, race, teeth_size='Min', eye_color=None, **kwargs):
super().__init__(**kwargs)
self.race = race
self.eye_color = eye_color
self.teeth_size = teeth_size
class PoliceDog(Dog):
def __init__(self, *, department, **kwargs):
kwargs['race'] = 'pitbull_terrier'
super().__init__(**kwargs)
PoliceAcademy().train(self)
class ScaryDog(Dog):
def __init__(self, **kwargs):
kwargs['teeth_size'] = 'MAX'
kwargs['eye_color'] = fetch_angry_eye_colors('https://dogs.com')
super().__init__(**kwargs)
self.experience_unhappy_childhood()
class ScaryPoliceDog(PoliceDog, ScaryDog):
pass
d = ScaryPoliceDog(department="vice")
除非有一些关于恐怖警犬的特定内容不适用于普通警犬或恐怖犬,否则在ScaryPoliceDog
中不需要做任何特别的事情。这一切都是通过使用 super
.
的委托来处理的
特别是:
ScaryPoliceDog
的 MRO 是 PoliceDog
、ScaryDog
、Dog
、object
。每个的 __init__
方法将依次调用。
PoliceDog
中的 super()
不是 指的是 Dog
;它指的是 ScaryDog
,因为那是 MRO 中 PoliceDog
之后的 class。
ScaryPoliceDog
不需要指定种族。尽管 Dog
需要该字段,但 PoliceDog
会提供该字段,因为 PoliceDog.__init__
将首先被调用。
装饰器几乎 工作但是由于您希望您的修改在实例化之前和之后发生,它们将无法正确链接。而是定义一个可以在创建时链接在一起的通用修饰符的自定义系统:
from abc import ABC, abstractmethod
class DogModifier(ABC):
@abstractmethod
def mod_kwargs(self, **kwargs):
pass
@abstractmethod
def post_init(self, dog):
pass
class PoliceDog(DogModifier):
def __init__(self, department):
self._dept = department
def mod_kwargs(self, **kwargs):
kwargs['race'] = 'pitbull_terrier'
def post_init(self, dog):
PoliceAcademy(self._dept).train(dog)
class ScaryDog(DogModifier):
def mod_kwargs(self, **kwargs):
kwargs['teeth_size'] = 'MAX'
kwargs['eye_color'] = fetch_angry_eye_color('https://dogs.com')
def post_init(self, dog):
dog.experience_unhappy_childhood()
def create_dog(*modifiers, **dog_kwargs):
for m in modifiers:
m.mod_kwargs(**dog_kwargs)
dog = Dog(**dog_kwargs)
for m in modifiers:
m.post_init(dog)
return dog
# ...
police_dog = create_dog(PoliceDog('bomb squad'), kw1='a', kw2='b')
scary_dog = create_dog(ScaryDog(), kw1='x', kw2='y')
scary_police_dog = create_dog(PoliceDog('bomb squad'), ScaryDog(), kw1='z')
*代码仅作为示例显示 - 错误修正留作 reader
的练习
假设你有一堆工厂函数,每个函数做两件事:
- 修改或添加参数到 class 的初始化
- 之后对 class 实例做一些事情
例如
class Dog:
def __init__(self, **very_many_kwargs):
pass
def create_police_dog(department, **dog_kwargs):
dog_kwargs['race'] = 'pitbull_terrier'
dog = Dog(**dog_kwargs)
police_academy = PoliceAcademy()
police_academy.train(dog)
return dog
def create_scary_dog(**dog_kwargs):
dog_kwargs['teeth_size'] = 'MAX'
dog_kwargs['eye_color'] = fetch_angry_eye_colors('https://dogs.com')
dog = Dog(**dog_kwargs)
dog.experience_unhappy_childhood()
return dog
如何串联多个这样的函数?
我认为我的解决方案不是最好的,并且对任何其他解决方案都非常感兴趣。但这是我的想法:
class DogFactory:
def __init__(self):
self.dog_kwargs = {}
self.dog_functions = []
def scary(self):
self.dog_kwargs['teeth_size'] = 'MAX'
self.dog_kwargs['eye_color'] = fetch_angry_eye_colors('https://dogs.com')
self.dog_functions.append(Dog.experience_unhappy_childhood)
return self
def police(self):
self.dog_kwargs['race'] = 'pitbull_terrier'
police_academy = PoliceAcademy()
self.dog_functions.append(police_academy.train)
return self
def create(self):
dog = Dog(**self.dog_kwargs)
for f in self.dog_functions:
f(dog)
return dog
dog = DogFactory() \
.scary() \
.police() \
.create()
每个函数都应该接受 Dog
的 现有 实例并修改它,然后 return 修改后的实例。这样,您就可以简单地组合函数。 (这在某种程度上相当于 Builder 模式的功能,尽管下面的示例有些笨拙和笨拙。)
class Dog:
def __init__(self, **very_many_kwargs):
pass
def create_police_dog(dog, department):
dog.race = 'pitbull_terrier'
police_academy = PoliceAcademy()
police_academy.train(dog)
return dog
def create_scary_dog(dog):
dog.teeth_size = 'MAX'
dog.eye_color = fetch_angry_eye_colors('https://dogs.com')
dog.experience_unhappy_childhood()
return dog
scary_police_dog = create_scary_dog(
create_police_dog(
Dog(),
'vice'
)
)
我认为这是构建器模式的一个更典型的实现。
class Dog:
...
class DogBuilder:
def __init__(self):
self.kwargs = {}
self._train = False
self._experience_unhappy_childhood = False
def build(self):
d = Dog(**self.kwargs)
if self._train:
PoliceAcademy().train(d)
if self._experience_unhappy_childhood:
d.experience_unhappy_childhood()
return d
def train(self):
self._train = True
def set_race(self, r):
self.kwargs['race'] = r
def experience_unhappy_childhood(self):
self._experience_unhappy_childhood = True
def make_police_dog(self, department):
self.kwargs['department'] = department
return self.set_race('pitbull_terrier').train()
def make_scary_dog(self):
return self.set_eye_color(fetch_angry_eye_colors('https://dogs.com')).
set_teeth_size('MAX').
experience_unhappy_childhood()
scary_police_dog = (DogBuilder()
.make_police_dog('vice')
.make_scary_dog()
.build()
这是一种使用多重继承的方法(更具体地说,合作多重继承)。
class Dog:
def __init__(self, *, race, teeth_size='Min', eye_color=None, **kwargs):
super().__init__(**kwargs)
self.race = race
self.eye_color = eye_color
self.teeth_size = teeth_size
class PoliceDog(Dog):
def __init__(self, *, department, **kwargs):
kwargs['race'] = 'pitbull_terrier'
super().__init__(**kwargs)
PoliceAcademy().train(self)
class ScaryDog(Dog):
def __init__(self, **kwargs):
kwargs['teeth_size'] = 'MAX'
kwargs['eye_color'] = fetch_angry_eye_colors('https://dogs.com')
super().__init__(**kwargs)
self.experience_unhappy_childhood()
class ScaryPoliceDog(PoliceDog, ScaryDog):
pass
d = ScaryPoliceDog(department="vice")
除非有一些关于恐怖警犬的特定内容不适用于普通警犬或恐怖犬,否则在ScaryPoliceDog
中不需要做任何特别的事情。这一切都是通过使用 super
.
特别是:
ScaryPoliceDog
的 MRO 是PoliceDog
、ScaryDog
、Dog
、object
。每个的__init__
方法将依次调用。super()
不是 指的是Dog
;它指的是ScaryDog
,因为那是 MRO 中PoliceDog
之后的 class。ScaryPoliceDog
不需要指定种族。尽管Dog
需要该字段,但PoliceDog
会提供该字段,因为PoliceDog.__init__
将首先被调用。
PoliceDog
中的 装饰器几乎 工作但是由于您希望您的修改在实例化之前和之后发生,它们将无法正确链接。而是定义一个可以在创建时链接在一起的通用修饰符的自定义系统:
from abc import ABC, abstractmethod
class DogModifier(ABC):
@abstractmethod
def mod_kwargs(self, **kwargs):
pass
@abstractmethod
def post_init(self, dog):
pass
class PoliceDog(DogModifier):
def __init__(self, department):
self._dept = department
def mod_kwargs(self, **kwargs):
kwargs['race'] = 'pitbull_terrier'
def post_init(self, dog):
PoliceAcademy(self._dept).train(dog)
class ScaryDog(DogModifier):
def mod_kwargs(self, **kwargs):
kwargs['teeth_size'] = 'MAX'
kwargs['eye_color'] = fetch_angry_eye_color('https://dogs.com')
def post_init(self, dog):
dog.experience_unhappy_childhood()
def create_dog(*modifiers, **dog_kwargs):
for m in modifiers:
m.mod_kwargs(**dog_kwargs)
dog = Dog(**dog_kwargs)
for m in modifiers:
m.post_init(dog)
return dog
# ...
police_dog = create_dog(PoliceDog('bomb squad'), kw1='a', kw2='b')
scary_dog = create_dog(ScaryDog(), kw1='x', kw2='y')
scary_police_dog = create_dog(PoliceDog('bomb squad'), ScaryDog(), kw1='z')
*代码仅作为示例显示 - 错误修正留作 reader
的练习