• 第七篇 设计模式


    一.简单工厂

       下面是简单工厂的UML图

     

    解释:

    有个CreateA类,它可以创建一个A类,这个A类可以是A1 ,也可以是A2,然后执行do方法

    简单工厂:你选择什么样的模式,就生成什么产品

    简单工厂模式(Simple Factory Pattern):是通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类.

    简单工厂的用处不大,主要就是一个if...else语句,写死的硬编码,想加功能必须改代码

    示例1

    # 根据不同的支付渠道选择对应的支付方式
    
    
    class Pay():
        def __init__(self,money):
            self.money = money
    
        def pay(self):
            print("京东金融支付{}元".format(self.money))
    
    class ZhiFuBao():
        def __init__(self, money):
            self.money = money
    
        def pay(self):
            print("支付宝支付{}元".format(self.money))
    
    
    class WeChat():
        def __init__(self, money):
            self.money = money
    
        def pay(self):
            print("微信支付{}元".format(self.money))
    
    channel = input("请输入支付方式:")
    money = input("请输入支付金额:")
    
    if channel == 'WeChat':
        WeChat(money).pay()
    elif channel == 'ZhiFuBao':
        ZhiFuBao(money).pay()
    else:
        Pay(money).pay()

    示例2:实现简单工厂,可以根据水果名生产对应的水果

    class Fruit(object):
        def __init__(self,name,price):
            self.name = name
            self.price = price
    
    
    class Apple(Fruit):
    
        def __init__(self,name,price):
            super(Apple,self).__init__(name,price)
            print("apple")
    
    class Peer(Fruit):
        def __init__(self,name,price):
            super(Peer,self).__init__(name,price)
            print("peer")
    
    
    class Banana(Fruit):
        def __init__(self,name,price):
            super(Banana, self).__init__(name,price)
            print("banana")
    
    class Watermelon(Fruit):
        def __init__(self,name,price):
            super(Watermelon, self).__init__(name,price)
            print("西瓜")
    
    
    
    # 简单工厂
    factory = input("请输入要生产的水果:")
    
    if factory == "Apple":
        Apple("红元帅",12)  # 实例化
    
    elif factory == "Peer":
        Peer("雪花梨",2.5)
    
    elif factory == "Banana":
        Banana("小芭蕉",5)
    
    elif factory == "Watermelon":
        Watermelon("小麒麟",1.8)

    二. 工厂方法

     

    工厂方法最大的特点: 把对象的获取和对象的创建给隔离开了

    1. 定义工厂方法

    # 1。 先定义每个产品(方法)的具体生产细节
    class JingDongJinRong():
        # 传参处理方式一:有构造函数,构造柱函数接受参数了,所以对应到下面的工厂方法里,也需要在create的时候就传参
        def __init__(self,money):
            self.money = money
    
        def pay(self):
            print("收到京东金融支付的{}元".format(self.money))  # 有初始化函数接受参数,此处就是self.money参数
    
    
    class ZhiFuBao():
        # 关于传参的处理方式二:直接就没有构造函数,只在具体的方法里接受参数,所以对应到下面的工厂方法里,也可不传参
        def pay(self,money):
            print("收到支付宝支付的{}元".format(money))  # 无初始化函数接收参数,而是方法直接接受参数,此处直接就是参数名,不加self
    
    class WeChat():
        def pay(self,money):
            print("收到微信支付的{}元".format(money))
    
    # 2. 再给每个产品定义一个特定的生产工厂,该生产工厂有具体的工厂方法,负责返回具体的工厂方法函数
    class JingDongJinRongFactory():
        # 传参处理方式一:
        # 因为JingDongJinRong()类是需要传参的,return其实就是先调用JingDongJinRong()类,将JingDongJinRong()执行结果返回,所以也需要传参
        # 因此,可以在create的时候就传递参数
        def create(self,money):
            return JingDongJinRong(money)
    
    
    class ZhiFuBaoFactory():
        # 关于传参的处理方式二:
        # ZhiFuBao()没有构造函数,初始化的时候不接收参数,所以对外提供的接口不需要传参
        # 只有在调用ZhiFuBao下面具体的pay()方法时才需要传递参数
        def create(self):
            return ZhiFuBao()
    
    class WeChatFactory():
        def create(self):
            return WeChat()

    2. 使用工厂方法

    # 使用京东金融支付工厂方法前,需要先导入工厂方法里的对应工厂
    from FactoryMethodDefined import JingDongJinRongFactory
    
    jindongjinrongfactory = JingDongJinRongFactory()  # 先实例化,类似于获取工厂
    # 传参处理方式一:在调用create的时候就给create传递参数
    payment_jingdong = jindongjinrongfactory.create(200) # 再调用创造工厂的函数,调工厂去创建具体的产品
    payment_jingdong.pay() # 有了具体的产品,就可以执行具体产品里具体的生产逻辑了
    
    
    # 使用支付宝工厂方法前,先导入支付宝工厂
    from FactoryMethodDefined import ZhiFuBaoFactory
    zhifubaofactory = ZhiFuBaoFactory()
    payment_zhifubao = zhifubaofactory.create()
    # 传参处理方式二:只在调用具体方法的时候给需要传参的方法才传递参数
    payment_zhifubao.pay(100)
    
    from FactoryMethodDefined import WeChatFactory
    wechatfactory = WeChatFactory()
    payment_wechat = wechatfactory.create()
    payment_wechat.pay(500.99)

     示例2:水果工厂

    1. 为每个具体产品创建工厂类,每个工厂类里有个创建的方法,返回具体的产品

    class Fruit(object):
        def __init__(self,name,price):
            self.name = name
            self.price = price
    
    
    class Apple(Fruit):
    
        def __init__(self,name,price):
            super(Apple,self).__init__(name,price)
            print("apple")
    
        def sweet(self):
            print("{}一斤的{}真是甜那".format(self.price,self.name))
    
    class Peer(Fruit):
        def __init__(self,name,price):
            super(Peer,self).__init__(name,price)
            print("peer")
    
    
    class Banana(Fruit):
        def __init__(self,name,price):
            super(Banana, self).__init__(name,price)
            print("banana")
    
    class Watermelon(Fruit):
        def __init__(self,name,price):
            super(Watermelon, self).__init__(name,price)
            print("西瓜")
    
    
    # 定义工厂
    class AppleFactory():
        # 这是套路,固定写法了
        def create(self,name,price):
            return Apple(name,price)
    
    
    class PeerFactory():
        def create(self,name,price):
            return Apple(name,price)
    
    class BananaFactory():
        def create(self,name,price):
            return Apple(name,price)
    
    class WatermelonFactory():
        def create(self,name,price):
            return Apple(name,price)

    2. 工厂方法的使用

    from fruitFactoryDefined import AppleFactory
    
    applefactory = AppleFactory()
    apple = applefactory.create("苹果",12)
    apple.sweet()

    三. 抽象工厂(一定要掌握的设计模式)

    抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的类

    抽象工厂最大的优点是:代码量少了很多,通过反射的方法就可以找出函数,比如在单元测试框架里,抽象方法是大量使用到的。

    在抽象工厂就是利用反射机制实现的,反射是非常重要的,会大量使用到

    抽象工厂最大的特点:不像工厂方法或者简单工厂那样需要硬编码,抽象工厂知道文件名、类名,通过反射的方式就是搞到方法。

    1. 反射

    什么是反射?

    反射就是通过字符串的形式,导入模块;通过字符串的形式,去模块寻找指定函数,并执行。利用字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员,一种基于字符串的事件驱动!

    上面的概念指出了使用反射需要掌握的知识点:

        a.通过字符串的形式,导入模块——>要用到:__import__()

        b.通过字符串的形式,去模块寻找指定函数并执行 ——> 用要到:getattr()

        c.利用字符串的形式去对象(模块)中操作(查找/获取/删除/添加)成员——>要用到:setattr(),hasattr(),delattr()

    了解掌握上面5个函数是反射的前提。

    (1) __import__()

          作用: __import__()可以实现以字符串的形式动态导入模块的目的

          上面通过 from... import...  或者 import ... 最终都会解释成 __import__(),所以,也就可以直接使用 __import__()去导入模块

    # 导入一个模块名,其实是.py文件名
    model = __import__("FactoryMethodDefined")
    print(model)
    # 输出 返回的是模块的路径
    <module 'FactoryMethodDefined' from '/Users/qiaoersun/Documents/千万别删/测试/Codes/testfanStudyPractice/lesson4_0623/FactoryMethodDefined.py'>
    
    # 查看导入的模块里都有什么
    print(dir(model))
    # ['JingDongJinRong', 'JingDongJinRongFactory', 'WeChat', 'WeChatFactory', 'ZhiFuBao', 'ZhiFuBaoFactory', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']

    上面的写法还是不够灵活,有这样一个需求, 需动态输入一个模块名(当然输入的就是字符串了),可以随时访问到导入模块中的方法或者变量,怎么做呢?

    就要用到__import__()方法

    modelName = input("请输入要导入的模块名:")
    
    mod = __import__(modelName)
    print(mod)
    # 输出
    <module 'FactoryMethodDefined' from '/Users/qiaoersun/Documents/千万别删/测试/Codes/testfanStudyPractice/lesson4_0623/FactoryMethodDefined.py'>
    
    
    print(dir(mod))
    # 输出
    ['JingDongJinRong', 'JingDongJinRongFactory', 'WeChat', 'WeChatFactory', 'ZhiFuBao', 'ZhiFuBaoFactory', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']

      (2)getattr()

    modelName = input("请输入要导入的模块名:")
    
    mod = __import__(modelName)
    
    
    # 上面有了导入,如果想看模块或者文件里有什么内容,怎么获取呢?
    object = getattr(mod,"ZhiFuBao")
    print(object)  # <class 'FactoryMethodDefined.ZhiFuBao'> 是个类
    print(object()) #<FactoryMethodDefined.ZhiFuBao object at 0x1046c7828> 就是个对象了
    # 调用方法
    object().pay(400)  # 收到支付宝支付的400元

    但是,这样相当于写死了,还是不够灵活,更灵活的处理如下

    modelName = input("请输入要导入的模块名:")
    class_ = input("请输入类型名:")
    mod = __import__(modelName)
    object = getattr(mod,class_)
    object().pay(400)  

    (3)hasattr(object, name)

    判断对象object是否包含名为name的特性(hasattr是通过调用getattr(ojbect, name)是否抛出异常来实现的)

    object:表示对象,可以是类名,也可以是实例名

    name: 属性名,是个字符串形式的

    class Test():
        def __init__(self,price):
            self.price = price
    
        def unitTest(self):
            print("pass")
    
    
    test = Test(66.66)
    print(hasattr(test,"price"))   # True
    print(getattr(test,"price"))   # 66.66
    
    test.name = "奥迪"
    print(hasattr(test,"name"))   # True
    print(getattr(test,"name"))   # 奥迪
    print(hasattr(test,"unitTest")) # True
    print(hasattr(test,"price2")) # False
    print(getattr(test,"unitTest")) # <bound method Test.unitTest of <__main__.Test object at 0x10e7de198>>

    (4) delattr(object, name)

    与setattr()相关的一组函数。参数是由一个对象(记住python中一切皆是对象)和一个字符串组成的。
    string参数必须是对象属性名之一。该函数删除该obj的一个由string指定的属性。delattr(x, 'foobar')=del x.foobar

      object:表示对象,可以是类名,也可以是实例名

      name: 属性名,是个字符串形式的

    # 先删除属性
    delattr(test, 'name')
    # 再通过hasattr()查看该属性是否还存在
    print(hasattr(test,'name'))  # False
    
    # 注意:
    # 这不是真的删除,而是只在内存里操作

    (5)setattr(object, name, value)

    这是相对应的getattr()。参数是一个对象,一个字符串和一个任意值。字符串可能会列出一个现有的属性或一个新的属性。
    这个函数将值赋给属性的。该对象允许它提供。例如,setattr(x,“foobar”,123)相当于x.foobar = 123。
    setattr(test,"name","大众")
    print(test.name) # 大众
    print(getattr(test,"name")) #大众

    四. 单例模式(用的不多,但是要能背下来) 

    单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保一个类只能有一个实例存在。当你希望在整个系统中,某个类只能创建一个实例时,单例对象就能派上用场。

    常见的配置文件,数据库连接等都会用到单例模式

    实现单例模式有很多种方法

    1. 基于__new__方法实现(推荐使用,方便)---要背下来

    原理:当实例化一个对象时,是先执行了类的__new__方法(我们没写时,默认调用object.__new__)实例化对象;然后再执行类的__init__方法,对这个对象进行初始化,因此我们可以基于这个,改造__new__()方法,在__new__里控制他只返回一个对象,从而实现单例模式.

    class Singleton():
        def __new__(cls, *args, **kwargs):
            # "_instance" 是变量名,可以随便取
            if not hasattr(cls,"_instance"):
                cls._instance = super(Singleton,cls).__init__(cls)
                # 上面的写法等价于下面的写法
                # cls._instance = object.__init__(cls)
            return cls._instance
    
    
    # 验证
    single1 = Singleton()
    single2 = Singleton()
    print(id(single1))
    print(id(single2))
    
    
    # 单例的继承
    class Apple(Singleton):
        def apple(self):
            pass
    
    apple1 = Apple()
    apple2 = Apple()
    
    print(id(apple1))
    print(id(apple2))
    
    
    # 输出
    4469315672
    4469315672
    4469315672
    4469315672

    2.使用修饰器 实现单例模式---很多面试可能会问,要背下来

    基于闭包实现

    def Singleton2(cls,*args,**kwargs):
        instance = {}
        def get_instance():
            if cls not in instance:
                instance[cls] = cls(*args, **kwargs)
            return instance[cls]
        return get_instance
    
    
    @Singleton2
    def Apple():
        pass
    
    apple1 = Apple()
    apple2 = Apple()
    
    print(id(apple1))
    print(id(apple2))
    
    # 4522248280
    # 4522248280
  • 相关阅读:
    PostgreSQL缺省值
    PostgreSQL表的基本概念
    PostgreSQL调用函数
    4.2. PostgreSQL值表达式
    3.5. PostgreSQL继承
    3.4. PostgreSQL事务
    3.3. PostgreSQL外键
    3.2. PostgreSQL视图
    碰撞
    骨骼
  • 原文地址:https://www.cnblogs.com/victorm/p/11308140.html
Copyright © 2020-2023  润新知