设计模式_创建型模式

馋奶兔 提交于 2020-01-20 12:29:44

目录

创建型模式:

 

简单工厂模式

一、内容

不直接向客户端暴露对象创建的实现细节,而是通过一个工厂类来负责创建产品类的实例。

二、角色

  • 工厂角色(Creator)
  • 抽象产品角色(Product)
  • 具体产品角色(Concrete Product)

三、优点

  • 隐藏了对象创建的实现细节
  • 客户端不需要修改代码

四、缺点

  • 违反了单一职责原则,将创建逻辑集中到一个工厂类中
  • 当添加新产品时,需要修改工厂类代码,违反了开放封闭原则

五、代码示例

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)
简单工厂模式

 

工厂方法模式

一、内容

定义一个用于创建对象的接口(工厂接口),让子类决定实例化哪一个产品类

二、角色

  • 抽象工厂角色(Creator)
  • 具体工厂角色(Concrere Creator)
  • 抽象产品角色(Product)
  • 具体产品角色(Concrete Product)

工厂方法模式相比简单工厂模式将每个具体产品都对应一个具体工厂

三、优点

  • 每个具体产品都对应一个具体工厂类,不需要修改工厂类代码
  • 隐藏了对象创建的实现细节

四、缺点

  • 每增加一个具体产品类,就必须增加一个相应的具体工厂类

五、使用场景

  • 需要生产多种、大量复杂对象的时候
  • 需要降低耦合度的时候
  • 当系统的产品种类需要经常扩展的时候  

六、代码示例

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 PaymentFactory(metaclass=ABCMeta):
    @abstractmethod
    def create_payment(self):
        pass


class AlipayFactory(PaymentFactory):
    def create_payment(self):
        return Alipay()

class ApplePayFactory(PaymentFactory):
    def create_payment(self):
        return ApplePay()


apple = ApplePayFactory()
apple.create_payment().pay(100)

alipay = AlipayFactory()
alipay.create_payment().pay(300)


# 苹果支付100元
# 支付宝支付300元
工厂方法模式

 

抽象工厂模式

一、内容

定义一个工厂类接口,当工厂子类来创建一系列相关或相互依赖的对象

例:生产一部手机,需要手机壳、CPU、操作系统三类对象进行组装,其中每类对象都有不同的种类。对每个具体工厂,分别生产一部手机所需要的三个对象。

二、角色

  • 抽象工厂角色(Creator
  • 具体工厂角色(Concrete Creator
  • 抽象产品角色(Product
  • 具体产品角色(Concrete Product
  • 客户端(Client

相比工厂方法模式,抽象工厂模式中的每个具体工厂都产生一套产品

三、优点

  • 将客户端与类的具体实现相分离
  • 每个工厂创建了一个完整的产品系列,使得易于交换产品系列
  • 有利于产品的一致性(即产品之间的约束关系)

四、缺点

  • 难以支持新种类的(抽象)产品

五、使用场景

  •  系统要独立于产品的创建与组合时

  •  强调一系列相关的产品对象的设计以便进行联合使用时 

  •  提供一个产品类库,想隐藏产品的具体实现时

六、代码示例

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()
抽象工厂模式

 

创建者模式

一、内容

将一个复杂对象的构建与它表示分离,使得同样的构建过程可以创建不同的表示

二、角色

  • 抽象建造者
  • 具体建造者
  • 指挥者
  • 产品

建造者模式与抽象工厂模式相似,也用来创建复杂对象。主要区别是建造者模式着重一步步构造一个复杂对象,而抽象工厂模式着重于多个系列的产品对象。

三、优点

  • 隐藏了一个产品的内部结构和装配过程
  • 将构造代码与表示代码分开
  • 可以将构建过程进行更精细的控制

五、使用场景

  • 当创建复杂对象的算法(Director)应该独立于该对象的组成部分以及它们的装配方式(Builder)时
  • 当构造过程允许被构造的对象有不同的表示时(不同Builder

六、代码示例

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)
创建者模式

 

原型模式

略。

单例模式

一、内容

  • 保证一个类只有一个实例,并提供一个访问它的全局访问点

二、角色

  • 单利

三、使用场景

  • 当类只有一个实例而且客户可以从一个众所周知的访问点访问它时
  • 比如:数据库链接、Socket创建链接

四、优点

  • 对唯一实例的受控访问
  • 单利相当于全局变量,但防止了命名空间被污染

与单利模式功能相似的概念:全局变量、静态变量(方法)

试问?为什么用单例模式,不用全局变量呢?

  答、全局变量可能会有名称空间的干扰,如果有重名的可能会被覆盖

五、单例模式的几种实现方式

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)
基于__new__实现的单例模式(最常用)
class Singleton(object):
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            # cls._instance = super(Singleton, cls).__new__(cls)
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
        return cls._instance



class Foo(Singleton):
    pass

a = Foo()
b = Foo()
c = Foo()
print(a is b)  # True
print(a,id(a),a.__dict__)  # <__main__.Foo object at 0x04E64910> 82200848 {}
print(b,id(b),b.__dict__)  # <__main__.Foo object at 0x04E64910> 82200848 {}
print(c,id(c),c.__dict__)  # <__main__.Foo object at 0x04E64910> 82200848 {}
继承模式实现

4、使用装饰器

def singleton(cls):
    instances = {}
    def wrapper(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    return wrapper
@singleton
class Foo(object):
    pass
foo1 = Foo()
foo2 = Foo()
print(foo1 is foo2)  # True
print(foo1,id(foo1),foo1.__dict__)  # <__main__.Foo object at 0x05448530> 88376624 {}
print(foo2,id(foo2),foo2.__dict__)  # <__main__.Foo object at 0x05448530> 88376624 {}
装饰器实现单例

5、基于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 Singleton(type):
    def __call__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            cls._instance = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instance
class Foo(object,metaclass=Singleton):
    def __init__(self,name):
        self.name = name

a = Foo("a")
b = Foo("b")
print(a,id(a),a.__dict__)  # <__main__.Foo object at 0x058B4910> 93014288 {'name': 'a'}
print(b,id(b),b.__dict__)  # <__main__.Foo object at 0x058B4910> 93014288 {'name': 'a'}



# 支持多线程
import threading

class Singleton(type):
    _instance_lock = threading.Lock()
    def __call__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            with cls._instance_lock:
                if not hasattr(cls, '_instance'):
                    cls._instance = super(Singleton, cls).__call__(*args, **kwargs)
        print(cls._instance,id(cls._instance),cls._instance.__dict__)  # 查看是否生效
        return cls._instance

class Foo(object,metaclass=Singleton):
    def __init__(self,name):
        self.name = name

for i in range(3):
    t = threading.Thread(target=Foo,args=(i,))
    t.start()

# <__main__.Foo object at 0x049C8D30> 77368624 {'name': 0}
# <__main__.Foo object at 0x049C8D30> 77368624 {'name': 0}
# <__main__.Foo object at 0x049C8D30> 77368624 {'name': 0}
基于metaclass(元类)实现的单例模式

六、单例模式的应用(会在数据库连接池中用到单例模式),详见以下示例操作

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()
pool.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()
app.py
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!