一.简单工厂

   下面是简单工厂的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
02-12 14:21