zoukankan      html  css  js  c++  java
  • 设计模式之原型模式

    一、理解原型模式

       原型模式就是帮助创建对象的克隆,有时候需要在对象的副本上进行操作,这样不会改变原对象的变量。假如figt和lice是两位厨师,现在figt有一份关于红烧肉的配料,他想分享给lice,那么如果lice想在配料谱上做修改,是否figt拿到的也会跟着变呢?

      如果是上图这样的表示figt与lice对同一个配料谱的引用,如果lice做了修改,figt看到的就是修改过后的内容,而且修改的时间不同,内容可能也会不同。但是这是不希望看到的,lice应该拥有figt的副本,这样修改自己的对figt没有影响。

    如上所示,这样lice就拥有自己的副本了,随意修改,不影响figt。在python中可以通过copy.deepcopy来完成。

    二、原型模式的实现

    import copy
    class A:
    
        def __init__(self):
            self.x=3
    
    if __name__=="__main__":
        a=A()
        b=copy.deepcopy(a)
        print(a)
        print(b)
        
    ##################输出###########
    #<__main__.A object at 0x00000000004F6828>
    #<__main__.A object at 0x00000000004F68D0>

    使用deepcopy函数算是比较简单的完成原型模式,可以看到两个对象的地址不同,说明已经完成了a对象的副本了。

    三、应用案例

     现在新建一个书籍相关的类,并且创建对象,然后利用这个对象再创建一个副本,并且可以在副本上进行修改。

    from collections import OrderedDict
    import time, hashlib
    class Book:
    
        def __init__(self,name,authors,price,**kwargs):
            """
            :param name:
            :param authors:
            :param price:
            :param kwargs: 出版商、出版日期等,关键词的形式(名称=值)传入更多的参数
            """
            self.name=name
            self.authors=authors
            self.price=price
            self.__dict__.update(kwargs)
    
    
        def create(self):
            """
            给自己对象创建一个唯一id
            :return:
            """
            m = hashlib.md5()
            m.update(bytes(str(time.time()), encoding="utf-8"))
            return m.hexdigest()
    
    
        def __str__(self):
            list=[]
            ordered = OrderedDict(sorted(self.__dict__.items())) #每次打印出对象的内容不会改变顺序
            for i in ordered.keys():
                list.append("%s:%s"%(i,ordered[i]))
                if i=="price":
                    list.append("$")
                list.append("
    ")
            return "".join(list)

    然后再创建一个专门用于clone的类Prototype

    import copy
    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] #删除对象的引用,触发析构方法__del__
    
        def clone(self,identifier,**attr): #attr用于在副本上进行修改,添加其它参数
    
            found=self.objects.get(identifier)
            if not found:
                raise ValueError('Incorrect object identifier: {}'.format(identifier))
            obj=copy.deepcopy(found)
            obj.__dict__.update(attr)
            return obj

    然后可以进行实例以及调用方法

    b1=Book("Python设计","Bjg",20,pub_date="2018-03-01") #实例化Book类
    b1_id=b1.create()#生成b1对象id
    
    prototype=Prototype()
    prototype.register(b1_id,b1) #将对象与id进行绑定
    
    b2=prototype.clone(b1_id,edition=3) #获取b1的副本,并且对副本进行了修改,添加edition=3
    
    print(b1)
    print(b1.__dict__)
    print(b2)
    print(b2.__dict__)
    ######################输出###############
    # authors:Bjg
    # name:Python设计
    # price:20$
    # pub_date:2018-03-01
    #
    # {'price': 20, 'name': 'Python设计', 'pub_date': '2018-03-01', 'authors': 'Bjg'}
    
    
    # authors:Bjg
    # edition:3
    # name:Python设计
    # price:20$
    # pub_date:2018-03-01
    #
    # {'edition': 3, 'name': 'Python设计', 'authors': 'Bjg', 'pub_date': '2018-03-01', 'price': 20}

     参考:精通Python设计模式一书

  • 相关阅读:
    二进制求和
    删除排序数组中的重复项--leetcode算法题
    vue render
    数字实现千分位分隔符
    用nodejs实现向文件的固定位置插入内容
    工作中用到的正则表达式
    组件toast(类似于element-ui的message组件)的实现
    用svg实现一个环形进度条
    批量删除当前文件夹下面的.svn文件夹
    windows下的包管理器scoop
  • 原文地址:https://www.cnblogs.com/shenjianping/p/11093220.html
Copyright © 2011-2022 走看看