【设计模式】创建型设计模式

一、简单工厂模式

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()

六、总结

依赖于继承的创建型模式:工厂方法模式
依赖于组合的创建型模式:抽象工厂模式,创建者模式
posted @ 2019-08-24 16:28  与凯学习  阅读(121)  评论(0)    收藏  举报