原型模式
- 当一个现有对象需要保持不变,而我们想创建它的精确副本时,以便更改副本的某些部分时,原型模式非常有用
- python实现原型模式基于
deepcopy()
方法
代码实现
import copy
class Website:
def __init__(self, name, domain, description, author, **kwargs):
'''Examples of optional attributes (kwargs):
category, creation_date, technologies, keywords.
'''
self.name = name
self.domain = domain
self.description = description
self.author = author
for key in kwargs:
setattr(self, key, kwargs[key])
def __str__(self):
summary = [f'Website "{self.name}"\n',]
infos = vars(self).items()
ordered_infos = sorted(infos)
for attr, val in ordered_infos:
if attr == 'name':
continue
summary.append(f'{attr}: {val}\n')
return ''.join(summary)
class Prototype:
def __init__(self):
self.objects = dict()
def register(self, identifier, obj):
self.objects[identifier] = obj
def unregister(self, identifier):
del self.objects[identifier]
def clone(self, identifier, **attrs):
found = self.objects.get(identifier)
if not found:
raise ValueError(f'Incorrect object identifier: {identifier}')
obj = copy.deepcopy(found)
for key in attrs:
setattr(obj, key, attrs[key])
return obj
def main():
keywords = ('python', 'data', 'apis', 'automation')
site1 = Website('ContentGardening',
domain='contentgardening.com',
description='Automation and data-driven apps',
author='Kamon Ayeva',
category='Blog',
keywords=keywords)
prototype = Prototype()
identifier = 'ka-cg-1'
prototype.register(identifier, site1)
site2 = prototype.clone(identifier,
name='ContentGardeningPlayground',
domain='play.contentgardening.com',
description='Experimentation for techniques featured on the blog',
category='Membership site',
creation_date='2018-08-01')
for site in (site1, site2):
print(site)
print(f'ID site1 : {id(site1)} != ID site2 : {id(site2)}')
if __name__ == '__main__':
main()
- 首先,导入copy模块
- 定义Website类,并添加前文所示的初始化方法(
__init__
())和字符串展示方法(__str__()
) - 定义Prototype类
- 添加main函数
- 定义我们需要的keywords
- 创建Website类的实例,名为site1
- 创建Proptotype对象,并使用它的register()方法来注册site1及其标识符
- 克隆site1对象,获得site2对象
- 展示结果,通过查看id发现是两个不同的对象
单例模式
- 只需要创建一个对象,或者需要某种能够维护程序全局状态的对象时,单例设计模式非常有用
- 控制对共享资源的并发访问。例如,负责管理与数据库间连接的类
- 横向的服务或资源,即它可以从应用程序的不同部分访问,也可以由不同的用户访问并执行其工作。例如,位于日志系统或实用程序库核心的类。
实现
- 首先为单例模式实现一个元类,其中元类的
__call()__
方法确保只能创建一个类实例 - 继承元类
代码实现
import urllib.parse
import urllib.request
class SingletonType(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(SingletonType, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class URLFetcher(metaclass=SingletonType):
def __init__(self):
self.urls = []
def fetch(self, url):
req = urllib.request.Request(url)
with urllib.request.urlopen(req) as response:
if response.code == 200:
the_page = response.read()
print(the_page)
urls = self.urls
urls.append(url)
self.urls = urls
def dump_url_registry(self):
return ', '.join(self.urls)
def main():
MY_URLS = ['http://www.voidspace.org.uk',
'http://google.com',
'http://python.org',
'https://www.python.org/error',
]
print(URLFetcher() is URLFetcher())
fetcher = URLFetcher()
for url in MY_URLS:
try:
fetcher.fetch(url)
except Exception as e:
print(e)
print('-------')
done_urls = fetcher.dump_url_registry()
print(f'Done URLs: {done_urls}')
if __name__ == '__main__':
main()