【设计模式】创建型设计模式
一、简单工厂模式
1.1概念
在简单工厂模式中,可以根据参数的不同返回不同实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
1.2角色
工厂角色(Creator):是此模式的核心类,内部提供静态工厂方法,用于创建所需产品对象,可被外界直接调用。
抽象产品角色(Product):是工厂类创建的所有对象的父类或共有的接口,封装各种产品对象的公有方法。
具体产品角色(Concrete Product):是此模式的创建目标,每个具体产品都继承了抽象产品角色,实现抽象产品角色中的抽象方法。
1.3优点
隐藏了对象创建的实现细节
客户端不需要修改代码
1.4缺点
违反了单一职责原则,将创建逻辑集中到一个工厂类中
当添加新产品时,需要修改工厂类代码,违反了开放封闭原则
1.5图解

1.6代码示例
1、初始化
from abc import abstractmethod,ABCMeta
class Payment(metaclass=ABCMeta):
@abstractmethod
def pay(self):
pass
class Alipay(Payment):
def __init__(self,money):
self.money = money
def pay(self):
print('支付宝支付了%s元'%self.money)
class Whatpay(Payment):
def __init__(self, money):
self.money = money
def pay(self):
print('微信支付了%s元' % self.money)
obj = Alipay(100)
obj.pay()
obj2 = Whatpay(200)
obj2.pay()
2、简单工厂模式
from abc import abstractmethod,ABCMeta
class Payment(metaclass=ABCMeta):
@abstractmethod
def pay(self,money):
pass
class Alipay(Payment):
def pay(self, money):
print('支付宝支付了%s元'%money)
class Applepay(Payment):
def pay(self, money):
print('微信支付了%s元' %money)
class Yuebao(Payment):
def pay(self,money):
print('余额宝支付了%s元' %money)
class PaymentFactory:
'''工厂类:封装了对象创建的细节'''
def create_payment(self,method):
if method =='alipay':
return Alipay()
elif method =='applepay':
return Applepay()
elif method =='yuebao':
return Yuebao()
else:
return NameError(method)
factory = PaymentFactory()
alipay=factory.create_payment('yuebao')
alipay.pay(100)
1.6 总结:
1、简单工厂模式实现了对象的“创建”和“使用”的分离,遵循了“单一职责原则”,但增加新的产品对象时须修改工厂类静态方法,违背了“开闭原则”
2、工厂类集中了所有产品创建逻辑(几乎是全能的),一旦不能工作,整个系统影响很大。
3、工厂类中使用了静态工厂方法,造成该类方法无法形成基于继承的等级结构。
二、工厂方法模式
2.1概念
定义一个用于创建对象的接口,但是让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。
2.2角色
抽象工厂角色(Creator)
在抽象工厂类中声明了工厂方法( Factory Method),用于返回一个产品。抽象工厂是工厂方法模式的核心,所有创建对象的工厂类都必须实现该接口。
具体工厂角色(Concrere Creator)
它是抽象工厂类的子类,实现了在抽象工厂中声明的工厂方法,并可由客户端调用,返回一个具体产品类的实例
抽象产品角色(Product)
它是定义产品的接口,是工厂方法模式所创建对象的超类型,也就是产品对象的公共父类
具体产品角色(Concrete Product)
它实现了抽象产品接口,某种类型的具体产品由专门的具体工厂创建,具体工厂和具体产品之间一一对应
2.3优点
每个具体产品都对应一个具体工厂类,不需要修改工厂类代码
隐藏了对象创建的实现细节
2.4缺点
每增加一个具体产品类,就必须增加一个相应的具体工厂类
2.5使用场景
需要生产多种、大量复杂对象的时候
需要降低耦合度的时候
当系统的产品种类需要经常扩展的时候
2.6图解

2.7代码示例
from abc import ABCMeta,abstractmethod
class PaymentFactory(metaclass=ABCMeta):
@abstractmethod
def create_payment(self):
pass
class Payment(metaclass=ABCMeta):
@abstractmethod
def pay(self,money):
pass
class Alipay(Payment):
def pay(self, money):
print('支付宝支付了%s元'%money)
class Applepay(Payment):
def pay(self, money):
print('微信支付了%s元' %money)
class AlipayFactory(PaymentFactory):
def create_payment(self):
return Alipay()
class AppleFactory(PaymentFactory):
def create_payment(self):
return Applepay()
apple = AppleFactory()
apple.create_payment().pay(100)
alipay = AlipayFactory()
alipay.create_payment().pay(300)
#输出
# 微信支付了100元
# 支付宝支付了300元
三、抽象工厂模式
3.1概念
定义一个工厂类接口,当工厂子类来创建一系列相关或相互依赖的对象
例:生产一部手机,需要手机壳、CPU、操作系统三类对象进行组装,其中每类对象都有不同的种类。对每个具体工厂,分别生产一部手机所需要的三个对象。
1、意图
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
2、主要解决
在一个产品族里面,定义多个产品。每个具体的工厂负责一个产品族。抽象工厂的返回值为最高级抽象产品
3、如何使用
系统的产品有多于一个的产品族,而系统只消费其中某一族的产品
4、如何解决
在一个产品族里面,定义多个产品
3.2角色
抽象工厂角色(Creator)
具体工厂角色(Concrete Creator)
抽象产品角色(Product)
具体产品角色(Concrete Product)
客户端(Client)
3.3优点
将客户端与类的具体实现相分离
每个工厂创建了一个完整的产品系列,使得易于交换产品系列
有利于产品的一致性(即产品之间的约束关系)
3.4缺点
难以支持新种类的(抽象)产品
3.5使用场景
系统要独立于产品的创建与组合时
强调一系列相关的产品对象的设计以便进行联合使用时
提供一个产品类库,想隐藏产品的具体实现时
抽象工厂,非常适合解决两个维度的组合产品的构造问题,取其中一个维度作为产品族,另外一个维度作为产品族中具体的多个产品。
3.6图解

3.7代码示例
from abc import abstractmethod,ABCMeta
#==============抽象产品============
class PhoneShell(metaclass=ABCMeta):
'''手机壳'''
@abstractmethod
def show_shell(self):
pass
class CPU(metaclass=ABCMeta):
'''CPU'''
@abstractmethod
def show_cpu(self):
pass
class OS(metaclass=ABCMeta):
'''操作系统'''
@abstractmethod
def show_os(self):
pass
# ===============抽象工厂==============
class PhoneFactory(metaclass=ABCMeta):
@abstractmethod
def make_shell(self):
'''制作手机壳'''
pass
@abstractmethod
def make_cpu(self):
'''制作cpu'''
pass
@abstractmethod
def make_os(self):
'''制作手机壳'''
pass
# =================具体产品==============
class SmallShell(PhoneShell):
def show_shell(self):
print('普通手机小手机壳')
class BigShell(PhoneShell):
def show_shell(self):
print('普通手机大手机壳')
class AppleShell(PhoneShell):
def show_shell(self):
print('苹果手机壳')
class YingTeerCPU(CPU):
def show_cpu(self):
print('英特尔cpu')
class MediaCPU(CPU):
def show_cpu(self):
print('联发科cpu')
class AppleCPU(CPU):
def show_cpu(self):
print('苹果cpu')
class Android(OS):
def show_os(self):
print('Android系统')
class IOS(OS):
def show_os(self):
print('ios系统')
# ==============具体工厂================
class MiFactory(PhoneFactory):
def make_shell(self):
return SmallShell()
def make_cpu(self):
return AppleCPU()
def make_os(self):
return Android()
class HuaWeiactory(PhoneFactory):
def make_shell(self):
return BigShell()
def make_cpu(self):
return YingTeerCPU()
def make_os(self):
return Android()
# ===============使用===============
class Phone:
def __init__(self,cpu,os,shell):
self.cpu = cpu
self.os = os
self.shell = shell
def show_info(self):
print('手机信息')
self.cpu.show_cpu()
self.os.show_os()
self.shell.show_shell()
def make_phone(factory):
cpu = factory.make_cpu()
os = factory.make_os()
shell = factory.make_shell()
return Phone(cpu,os,shell)
p1 = make_phone(HuaWeiactory())
p1.show_info()
p2 = make_phone(MiFactory())
p2.show_info()
四、建造者模式
4.1概念
将一个复杂对象的构建与它表示分离,使得同样的构建过程可以创建不同的表示。
1、意图
将一个复杂对象的构建与它表示分离,使得同样的构建过程可以创建不同的表示
2、主要解决
主要解决接口选择的问题
3、如何使用
系统的产品有多于一个的产品族,而系统只消费其中某一族的产品
4、如何解决
在一个产品族里面,定义多个产品
4.2角色
抽象建造者
具体建造者
指挥者
产品
构建一个使用Builder接口的对象。它主要是用于创建一个复杂的对象。它主要有两个作用,一是:隔离了客户与对象的生产过程,二是:负责控制产品对象的生产过程。
4.3优点
隐藏了一个产品的内部结构和装配过程
将构造代码与表示代码分开
可以将构建过程进行更精细的控制
4.4缺点
难以支持新种类的(抽象)产品
4.5使用场景
当创建复杂对象的算法(Director)应该独立于该对象的组成部分以及它们的装配方式(Builder)时
当构造过程允许被构造的对象有不同的表示时(不同Builder)
4.6代码示例

4.7代码示例
import random
from abc import abstractmethod, ABCMeta
#------产品------
class Player:
def __init__(self, face=None, body=None, arm=None, leg=None):
self.face = face
self.arm = arm
self.leg = leg
self.body = body
def __str__(self):
return "%s, %s, %s, %s" % (self.face, self.arm, self.body, self.leg)
#------建造者------
class PlayerBuilder(metaclass=ABCMeta):
@abstractmethod
def build_face(self):
pass
@abstractmethod
def build_arm(self):
pass
@abstractmethod
def build_leg(self):
pass
@abstractmethod
def build_body(self):
pass
@abstractmethod
def get_player(self):
pass
class BeautifulWomanBuilder(PlayerBuilder):
def __init__(self):
self.player = Player()
def build_face(self):
self.player.face = "漂亮脸蛋"
def build_arm(self):
self.player.arm="细胳膊"
def build_body(self):
self.player.body="细腰"
def build_leg(self):
self.player.leg="长腿"
def get_player(self):
return self.player
class RandomPlayerBuilder(PlayerBuilder):
def __init__(self):
self.player = Player()
def build_face(self):
self.player.face = random.choice(["瓜子脸","西瓜子脸"])
def build_arm(self):
self.player.arm=random.choice(["长胳膊","短胳膊"])
def build_body(self):
self.player.body=random.choice(["苗条","胖"])
def build_leg(self):
self.player.leg=random.choice(["长腿","短腿"])
def get_player(self):
return self.player
class PlayerDirector:
def __init__(self, builder):
self.builder = builder
# 控制组装顺序
def build_player(self):
self.builder.build_body()
self.builder.build_face()
self.builder.build_arm()
self.builder.build_leg()
return self.builder.get_player()
pd = PlayerDirector(RandomPlayerBuilder())
p = pd.build_player()
print(p)
五、单例模式
5.1概念
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
1、意图
保证一个类仅有一个实例,并提供一个访问它的全局访问点
2、主要解决
一个全局使用的类频繁地创建与销毁
3、如何使用
当您想控制实例数目,节省系统资源的时候。
4、如何解决
判断系统是否已经有这个单例,如果有则返回,如果没有则创建
5、关键代码
构造函数是私有的
5.2角色
单利
5.3优点
对唯一实例的受控访问
单利相当于全局变量,但防止了命名空间被污染
为什么用单例模式,不用全局变量呢?
答、全局变量可能会有名称空间的干扰,如果有重名的可能会被覆盖
5.4缺点
难以支持新种类的(抽象)产品
5.5使用场景
当类只有一个实例而且客户可以从一个众所周知的访问点访问它时
比如:数据库链接、Socket创建链接
5.6单例模式的实现方式
1、文件导入形式
s1.py
class Foo(object):
def test(self):
print("123")
v = Foo()
#v是Foo的实例
s2.py
from s1 import v as v1
print(v1,id(v1)) #<s1.Foo object at 0x0000000002221710> 35788560
from s1 import v as v2
print(v1,id(v2)) #<s1.Foo object at 0x0000000002221710> 35788560
# 两个的内存地址是一样的
# 文件加载的时候,第一次导入后,再次导入时不会再重新加载。
2、基于类实现的单例模式
# ======================单例模式:无法支持多线程情况===============
class Singleton(object):
def __init__(self):
import time
time.sleep(1)
@classmethod
def instance(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance
import threading
def task(arg):
obj = Singleton.instance()
print(obj)
for i in range(10):
t = threading.Thread(target=task,args=[i,])
t.start()
# ====================单例模式:支持多线程情况================、
import time
import threading
class Singleton(object):
_instance_lock = threading.Lock()
def __init__(self):
time.sleep(1)
@classmethod
def instance(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
with Singleton._instance_lock: #为了保证线程安全在内部加锁
if not hasattr(Singleton, "_instance"):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance
def task(arg):
obj = Singleton.instance()
print(obj)
for i in range(10):
t = threading.Thread(target=task,args=[i,])
t.start()
time.sleep(20)
obj = Singleton.instance()
print(obj)
# 使用先说明,以后用单例模式,obj = Singleton.instance()
# 示例:
# obj1 = Singleton.instance()
# obj2 = Singleton.instance()
# print(obj1,obj2)
# 错误示例
# obj1 = Singleton()
# obj2 = Singleton()
# print(obj1,obj2)
3、基于new实现的单例模式
# =============单线程下执行===============
import threading
class Singleton(object):
_instance_lock = threading.Lock()
def __init__(self):
pass
def __new__(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
with Singleton._instance_lock:
if not hasattr(Singleton, "_instance"):
# 类加括号就回去执行__new__方法,__new__方法会创建一个类实例:Singleton()
Singleton._instance = object.__new__(cls) # 继承object类的__new__方法,类去调用方法,说明是函数,要手动传cls
return Singleton._instance #obj1
#类加括号就会先去执行__new__方法,在执行__init__方法
# obj1 = Singleton()
# obj2 = Singleton()
# print(obj1,obj2)
# ===========多线程执行单利============
def task(arg):
obj = Singleton()
print(obj)
for i in range(10):
t = threading.Thread(target=task,args=[i,])
t.start()
# 使用先说明,以后用单例模式,obj = Singleton()
# 示例
# obj1 = Singleton()
# obj2 = Singleton()
# print(obj1,obj2)
4、基于metaclass(元类)实现的单
"""
1.对象是类创建,创建对象时候类的__init__方法自动执行,对象()执行类的 __call__ 方法
2.类是type创建,创建类时候type的__init__方法自动执行,类() 执行type的 __call__方法(类的__new__方法,类的__init__方法)
# 第0步: 执行type的 __init__ 方法【类是type的对象】
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
pass
# 第1步: 执行type的 __call__ 方法
# 1.1 调用 Foo类(是type的对象)的 __new__方法,用于创建对象。
# 1.2 调用 Foo类(是type的对象)的 __init__方法,用于对对象初始化。
obj = Foo()
# 第2步:执行Foo的 __call__ 方法
obj()
"""
# ===========类的执行流程================
class SingletonType(type):
def __init__(self,*args,**kwargs):
print(self) #会不会打印? #<class '__main__.Foo'>
super(SingletonType,self).__init__(*args,**kwargs)
def __call__(cls, *args, **kwargs): #cls = Foo
obj = cls.__new__(cls, *args, **kwargs)
obj.__init__(*args, **kwargs)
return obj
class Foo(metaclass=SingletonType):
def __init__(self,name):
self.name = name
def __new__(cls, *args, **kwargs):
return object.__new__(cls, *args, **kwargs)
'''
1、对象是类创建的,创建对象时类的__init__方法会自动执行,对象()执行类的__call__方法
2、类是type创建的,创建类时候type类的__init__方法会自动执行,类()会先执行type的__call__方法(调用类的__new__,__init__方法)
Foo 这个类是由SingletonType这个类创建的
'''
obj = Foo("hiayan")
# ============第三种方式实现单例模式=================
import threading
class SingletonType(type):
_instance_lock = threading.Lock()
def __call__(cls, *args, **kwargs):
if not hasattr(cls, "_instance"):
with SingletonType._instance_lock:
if not hasattr(cls, "_instance"):
cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)
return cls._instance
class Foo(metaclass=SingletonType):
def __init__(self,name):
self.name = name
obj1 = Foo('name')
obj2 = Foo('name')
print(obj1,obj2)
5、用装饰器实现单例模式
def wrapper(cls):
instance = {}
def inner(*args,**kwargs):
if cls not in instance:
instance[cls] = cls(*args,**kwargs)
return instance[cls]
return inner
@wrapper
class Singleton(object):
def __init__(self,name,age):
self.name = name
self.age = age
obj1 = Singleton('haiyan',22)
obj2 = Singleton('xx',22)
print(obj1)
print(obj2)
5.7单例模式的应用
pool.py
import pymysql
import threading
from DBUtils.PooledDB import PooledDB
class SingletonDBPool(object):
_instance_lock = threading.Lock()
def __init__(self):
self.pool = PooledDB(
creator=pymysql, # 使用链接数据库的模块
maxconnections=6, # 连接池允许的最大连接数,0和None表示不限制连接数
mincached=2, # 初始化时,链接池中至少创建的空闲的链接,0表示不创建
maxcached=5, # 链接池中最多闲置的链接,0和None不限制
maxshared=3,
# 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。
blocking=True, # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错
maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制
setsession=[], # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
ping=0,
# ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
host='127.0.0.1',
port=3306,
user='root',
password='123',
database='pooldb',
charset='utf8'
)
def __new__(cls, *args, **kwargs):
if not hasattr(SingletonDBPool, "_instance"):
with SingletonDBPool._instance_lock:
if not hasattr(SingletonDBPool, "_instance"):
SingletonDBPool._instance = object.__new__(cls, *args, **kwargs)
return SingletonDBPool._instance
def connect(self):
return self.pool.connection()
app.py
from pool import SingletonDBPool
def run():
pool = SingletonDBPool()
conn = pool.connect()
# xxxxxx
cursor = conn.cursor()
cursor.execute("select * from td where id=%s", [5, ])
result = cursor.fetchall() # 获取数据
cursor.close()
conn.close()
if __name__ == '__main__':
run()
六、总结
依赖于继承的创建型模式:工厂方法模式
依赖于组合的创建型模式:抽象工厂模式,创建者模式

浙公网安备 33010602011771号