python原型模式和单例模式学习

原型模式

  • 当一个现有对象需要保持不变,而我们想创建它的精确副本时,以便更改副本的某些部分时,原型模式非常有用
  • 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()
  1. 首先,导入copy模块
  2. 定义Website类,并添加前文所示的初始化方法(__init__())和字符串展示方法(__str__()
  3. 定义Prototype类
  4. 添加main函数
    • 定义我们需要的keywords
    • 创建Website类的实例,名为site1
    • 创建Proptotype对象,并使用它的register()方法来注册site1及其标识符
    • 克隆site1对象,获得site2对象
    • 展示结果,通过查看id发现是两个不同的对象

单例模式

  • 只需要创建一个对象,或者需要某种能够维护程序全局状态的对象时,单例设计模式非常有用
  • 控制对共享资源的并发访问。例如,负责管理与数据库间连接的类
  • 横向的服务或资源,即它可以从应用程序的不同部分访问,也可以由不同的用户访问并执行其工作。例如,位于日志系统或实用程序库核心的类。

实现

  1. 首先为单例模式实现一个元类,其中元类的__call()__方法确保只能创建一个类实例
  2. 继承元类

代码实现

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()
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一切如来心秘密

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值