代理模式和黑板模式 20/30 | Python 主题月
写在前面
本文正在参加「Python主题月」,详情查看活动链接
这个月是 Python 活动月,我决定尝试用 Python 来刷这 30 天的每日一题和随机一题。然后如果周末有精力,我想捣鼓捣鼓这个python-patterns
设计模式对我来说更多的是学习而不是我的个人经验总结,所以我很可能理解偏,如果有大佬见到了请及时指出,我之所以选择在掘金来写一些个人的东西是因为这里的文章质量更高,我不希望后来者看到了这些文章被误导。
代理模式
from __future__ import annotations
from typing import Any, Callable, Union
class Delegator:
"""
>>> delegator = Delegator(Delegate())
>>> delegator.p1
123
>>> delegator.p2
Traceback (most recent call last):
...
AttributeError: 'Delegate' object has no attribute 'p2'
>>> delegator.do_something("nothing")
'Doing nothing'
>>> delegator.do_anything()
Traceback (most recent call last):
...
AttributeError: 'Delegate' object has no attribute 'do_anything'
"""
def __init__(self, delegate: Delegate):
self.delegate = delegate
def __getattr__(self, name: str) -> Union[Any, Callable]:
attr = getattr(self.delegate, name)
if not callable(attr):
return attr
def wrapper(*args, **kwargs):
return attr(*args, **kwargs)
return wrapper
class Delegate:
def __init__(self):
self.p1 = 123
def do_something(self, something: str) -> str:
return f"Doing {something}"
if __name__ == "__main__":
import doctest
doctest.testmod()
黑板模式
import abc
import random
class Blackboard:
def __init__(self):
self.experts = []
self.common_state = {
"problems": 0,
"suggestions": 0,
"contributions": [],
"progress": 0, # percentage, if 100 -> task is finished
}
def add_expert(self, expert):
self.experts.append(expert)
class Controller:
def __init__(self, blackboard):
self.blackboard = blackboard
def run_loop(self):
while self.blackboard.common_state["progress"] < 100:
for expert in self.blackboard.experts:
if expert.is_eager_to_contribute:
expert.contribute()
return self.blackboard.common_state["contributions"]
class AbstractExpert(metaclass=abc.ABCMeta):
def __init__(self, blackboard):
self.blackboard = blackboard
@property
@abc.abstractmethod
def is_eager_to_contribute(self):
raise NotImplementedError("Must provide implementation in subclass.")
@abc.abstractmethod
def contribute(self):
raise NotImplementedError("Must provide implementation in subclass.")
class Student(AbstractExpert):
@property
def is_eager_to_contribute(self):
return True
def contribute(self):
self.blackboard.common_state["problems"] += random.randint(1, 10)
self.blackboard.common_state["suggestions"] += random.randint(1, 10)
self.blackboard.common_state["contributions"] += [self.__class__.__name__]
self.blackboard.common_state["progress"] += random.randint(1, 2)
class Scientist(AbstractExpert):
@property
def is_eager_to_contribute(self):
return random.randint(0, 1)
def contribute(self):
self.blackboard.common_state["problems"] += random.randint(10, 20)
self.blackboard.common_state["suggestions"] += random.randint(10, 20)
self.blackboard.common_state["contributions"] += [self.__class__.__name__]
self.blackboard.common_state["progress"] += random.randint(10, 30)
class Professor(AbstractExpert):
@property
def is_eager_to_contribute(self):
return True if self.blackboard.common_state["problems"] > 100 else False
def contribute(self):
self.blackboard.common_state["problems"] += random.randint(1, 2)
self.blackboard.common_state["suggestions"] += random.randint(10, 20)
self.blackboard.common_state["contributions"] += [self.__class__.__name__]
self.blackboard.common_state["progress"] += random.randint(10, 100)
def main():
"""
>>> blackboard = Blackboard()
>>> blackboard.add_expert(Student(blackboard))
>>> blackboard.add_expert(Scientist(blackboard))
>>> blackboard.add_expert(Professor(blackboard))
>>> c = Controller(blackboard)
>>> contributions = c.run_loop()
>>> from pprint import pprint
>>> pprint(contributions)
['Student',
'Student',
'Student',
'Student',
'Scientist',
'Student',
'Student',
'Student',
'Scientist',
'Student',
'Scientist',
'Student',
'Student',
'Scientist',
'Professor']
"""
if __name__ == "__main__":
random.seed(1234) # for deterministic doctest outputs
import doctest
doctest.testmod()
小结
参考文献
- 无