python设计模式之设计类模式

一、单例模式

1、总线

"""
	总线是计算机各种功能部件或者设备之间传送数据、控制信号等信息的公共通信解决方案之一。现假设有如下场景:
	某中央处理器(CPU)通过某种协议总线与一个信号灯相连,信号灯有64种颜色可以设置,中央处理器上运行着三个线程,都可以对这个信号灯进行控制,并且可以独立设置该信号灯的颜色。抽象掉协议细节(用打印表示),如何实现线程对信号等的控制逻辑。
	加线程锁进行控制,无疑是最先想到的方法,但各个线程对锁的控制,无疑加大了模块之间的耦合。下面,我们就用设计模式中的单例模式,来解决这个问题。
"""

2、是什么

#  什么是单例模式?单例模式是指:保证一个类仅有一个实例,并提供一个访问它的全局访问点。具体到此例中,总线对象,就是一个单例,它仅有一个实例,各个线程对总线的访问只有一个全局访问点,即惟一的实例。

3、优缺点

#  单例模式的优点
1、由于单例模式要求在全局内只有一个实例,因而可以节省比较多的内存空间;
2、全局只有一个接入点,可以更好地进行数据同步控制,避免多重占用;
3、单例可长驻内存,减少系统开销。

#  单例模式的应用举例
1、生成全局惟一的序列号;
2、访问全局复用的惟一资源,如磁盘、总线等;
3、单个对象占用的资源过多,如数据库等;
4、系统全局统一管理,如Windows下的Task Manager;
5、网站计数器。

#  缺点
1、单例模式的扩展是比较困难的;
2、赋于了单例以太多的职责,某种程度上违反单一职责原则(六大原则后面会讲到);
3、单例模式是并发协作软件模块中需要最先完成的,因而其不利于测试;
4、单例模式在某种情况下会导致“资源瓶颈”。

二、工厂模式

1、快餐点餐系统

"""
	想必大家一定见过类似于麦当劳自助点餐台一类的点餐系统吧。在一个大的触摸显示屏上,有三类可以选择的上餐品:汉堡等主餐、小食、饮料。当我们选择好自己需要的食物,支付完成后,订单就生成了。下面,我们用今天的主角--工厂模式--来生成这些食物的逻辑主体。
"""

#  来看主餐的生成(仅以两种汉堡为例)
class Burger:
    name = ''
    price = 0

    def get_price(self):
        return self.price

    def set_price(self, price):
        self.price = price

    def get_name(self):
        return self.name


class CheeseBurger(Burger):
    def __init__(self):
        self.name = 'cheese burger'
        self.price = 10.0


class SpicyChickenBurger(Burger):
    def __init__(self):
        self.name = 'spicy chicken burger'
        self.price = 15.0


#  其次,是小食。(内容基本一致)
class Snack:
    name = ""
    price = 0.0
    type = "SNACK"

    def get_price(self):
        return self.price

    def set_price(self, price):
        self.price = price

    def get_name(self):
        return self.name


class Chips(Snack):
    def __init__(self):
        self.name = "chips"
        self.price = 6.0


class ChickenWings(Snack):
    def __init__(self):
        self.name = "chicken wings"
        self.price = 12.0


#  最后,是饮料。
class Beverage:
    name = ""
    price = 0.0
    type = "BEVERAGE"

    def get_price(self):
        return self.price

    def set_price(self, price):
        self.price = price

    def get_name(self):
        return self.name


class Coke(Beverage):
    def __init__(self):
        self.name = "coke"
        self.price = 4.0


class Milk(Beverage):
    def __init__(self):
        self.name = "milk"
        self.price = 5.0


"""
以上的Burger,Snack,Beverage,都可以认为是该快餐店的产品,由于只提供了抽象方法,
我们把它们叫抽象产品类,而cheese burger等6个由抽象产品类衍生出的子类,叫作具体产品类。
接下来,“工厂”就要出现了。
"""


class FoodFactory:
    Type = ''

    def create_food(self, food_class):
        print(self.Type, 'factory produce a instance')
        food_ins = food_class()
        return food_ins


class BurgerFactory(FoodFactory):
    def __init__(self):
        self.Type = 'BURGER'


class SnackFactory(FoodFactory):
    def __init__(self):
        self.Type = "SNACK"


class BeverageFactory(FoodFactory):
    def __init__(self):
        self.Type = "BEVERAGE"


"""
同样,foodFactory为抽象的工厂类,而burgerFactory,
snackFactory,beverageFactory为具体的工厂类。
在业务场景中,工厂模式是如何“生产”产品的呢?
"""

if __name__ == "__main__":
    burger_factory = BurgerFactory()
    snack_factory = SnackFactory()
    beverage_factory = BeverageFactory()

    cheese_burger = burger_factory.create_food(CheeseBurger)
    print(cheese_burger.get_name(), cheese_burger.get_price())
    print()
    chicken_wings = snack_factory.create_food(ChickenWings)
    print(chicken_wings.get_name(), chicken_wings.get_price())
    print()
    coke_drink = beverage_factory.create_food(Coke)
    print(coke_drink.get_name(), coke_drink.get_price())



BURGER factory produce a instance
cheese burger 10.0

SNACK factory produce a instance
chicken wings 12.0

BEVERAGE factory produce a instance
coke 4.0

进程已结束,退出代码 0

三、简单工厂模式、抽象工厂模式

"""
	工厂模式的定义如下:定义一个用于创建对象的接口,让子类决定实例化哪个类。工厂方法使一个类的实例化延迟到其子类。其通用类图如下。其产品类定义产品的公共属性和接口,工厂类定义产品实例化的“方式”。
"""

#  在上述例子中,工厂在使用前必须实例化。如果,把工厂加个类方法,写成如下形式:
class SimpleFoodFactory:
    @classmethod
    def create_food(cls,foodClass):
        print "Simple factory produce a instance."
        food_ins = food_class()
        return food_ins
    
"""
在场景中写成如下形式:
spicy_chicken_burger=SimpleFoodFactory.create_food(SpicyChickenBurger)
这样,省去了将工厂实例化的过程。这种模式就叫做简单工厂模式。
还是在上述例子中,createFood方法中必须传入foodClass才可以指定生成的food实例种类,如果,将每一个细致的产品都建立对应的工厂(如cheeseBurger建立对应一个cheeseBurgerFactory),这样,生成食物时,foodClass也不必指定。事实上,此时,burgerFactory就是具体食物工厂的一层抽象。这种模式,就是抽象工厂模式。
"""    

在这里插入图片描述
在这里插入图片描述

1、工厂模式的优点和应用

"""
工厂模式、抽象工厂模式的优点:
1、工厂模式具有非常好的封装性,代码结构清晰;在抽象工厂模式中,其结构还可以随着需要进行更深或者更浅的抽象层级调整,非常灵活;
2、屏蔽产品类,使产品的被使用业务场景和产品的功能细节可以分而开发进行,是比较典型的解耦框架。
工厂模式、抽象工厂模式的使用场景:
1、当系统实例要求比较灵活和可扩展时,可以考虑工厂模式或者抽象工厂模式实现。比如,
在通信系统中,高层通信协议会很多样化,同时,上层协议依赖于下层协议,那么就可以对应建立对应层级的抽象工厂,根据不同的“产品需求”去生产定制的实例。
"""

2、工厂类模式的不足

"""
1、工厂模式相对于直接生成实例过程要复杂一些,所以,在小项目中,可以不使用工厂模式;
2、抽象工厂模式中,产品类的扩展比较麻烦。毕竟,每一个工厂对应每一类产品,产品扩展,就意味着相应的抽象工厂也要扩展
"""

四、建造者模式

1、快餐点餐系统

"""
	今天的例子,还是上一次谈到的快餐点餐系统。只不过,今天我们从订单的角度来构造这个系统。
最先还是有请上次的主角们:	
"""
#  主餐

class Burger():
    name=""
    price=0.0
    def getPrice(self):
        return self.price
    def setPrice(self,price):
        self.price=price
    def getName(self):
        return self.name
class cheeseBurger(Burger):
    def __init__(self):
        self.name="cheese burger"
        self.price=10.0
class spicyChickenBurger(Burger):
    def __init__(self):
        self.name="spicy chicken burger"
        self.price=15.0

#  小食
class Snack():
    name = ""
    price = 0.0
    type = "SNACK"
    def getPrice(self):
        return self.price
    def setPrice(self, price):
        self.price = price
    def getName(self):
        return self.name


class chips(Snack):
    def __init__(self):
        self.name = "chips"
        self.price = 6.0


class chickenWings(Snack):
    def __init__(self):
        self.name = "chicken wings"
        self.price = 12.0

#  饮料
class Beverage():
    name = ""
    price = 0.0
    type = "BEVERAGE"
    def getPrice(self):
        return self.price
    def setPrice(self, price):
        self.price = price
    def getName(self):
        return self.name


class coke(Beverage):
    def __init__(self):
        self.name = "coke"
        self.price = 4.0


class milk(Beverage):
    def __init__(self):
        self.name = "milk"
        self.price = 5.0

#  最终,我们是要建造一个订单,因而,需要一个订单类。假设,一个订单,包括一份主食,一份小食,一种饮料。(省去一些异常判断)

class order:
    burger = ''
    snack = ''
    beverage = ''


    def __init__(self, orderBuilder):
        self.burger = orderBuilder.bBurger
        self.snack = orderBuilder.bSnack
        self.beverage = orderBuilder.bBeverage

    def show(self):
        print('Burger:%s' % self.burger.getName())
        print('Snack:%s' % self.snack.getName())
        print('Beverage:%s' % self.beverage.getName())


#  代码中的orderBuilder是什么鬼?
#  这个orderBuilder就是建造者模式中所谓的“建造者”了,
#  先不要问为什么不在order类中把所有内容都填上,而非要用builder去创建。
#  接着往下看。
# orderBuilder的实现如下:


class orderBuilder:
    bBurger = ''
    bSnack = ''
    bBeverage = ''

    def addBurger(self, xBurger):
        self.bBurger = xBurger

    def addSnack(self, xSnack):
        self.bSnack = xSnack

    def addBeverage(self, xBeverage):
        self.bBeverage = xBeverage

    def builder(self):
        s = order(self)
        return s


#  在场景中如下去实现订单的生成:
if __name__ == '__main__':
    order_builder = orderBuilder()
    order_builder.addBurger(spicyChickenBurger())
    order_builder.addSnack(chips())
    order_builder.addBeverage(milk())
    order_1 = order_builder.builder()
    order_1.show()
    
    
Burger:spicy chicken burger
Snack:chips
Beverage:milk

进程已结束,退出代码 0

2、建造者模式

"""
	建造者模式的定义如下:
	将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
	建造者模式的作用,就是将“构建”和“表示”分离,以达到解耦的作用。在上面订单的构建过程中,如果将order直接通过参数定义好(其构建与表示没有分离),同时在多处进行订单生成,此时需要修改订单内容,则需要一处处去修改,业务风险也就提高了不少。
	在建造者模式中,还可以加一个Director类,用以安排已有模块的构造步骤。对于在建造者中有比较严格的顺序要求时,该类会有比较大的用处。在上述例子中,Director实现如下:
"""

class orderDirector:
    order_builder=""
    def __init__(self,order_builder):
        self.order_builder=order_builder
    def createOrder(self,burger,snack,beverage):
        self.order_builder.addBurger(burger)
        self.order_builder.addSnack(snack)
        self.order_builder.addBeverage(beverage)
        return self.order_builder.build()
#  通过createOrder直接代入参数,即可直接生成订单。

在这里插入图片描述

3、建造者模式的优点和使用场景

"""
优点:
1、封装性好,用户可以不知道对象的内部构造和细节,就可以直接建造对象;
2、系统扩展容易;
3、建造者模式易于使用,非常灵活。在构造性的场景中很容易实现“流水线”;
4、便于控制细节。

使用场景:
1、目标对象由组件构成的场景中,很适合建造者模式。例如,在一款赛车游戏中,车辆生成时,需要根据级别、环境等,选择轮胎、悬挂、骨架等部件,构造一辆“赛车”;
2、在具体的场景中,对象内部接口需要根据不同的参数而调用顺序有所不同时,可以使用建造者模式。例如:一个植物养殖器系统,对于某些不同的植物,浇水、施加肥料的顺序要求可能会不同,因而可以在Director中维护一个类似于队列的结构,在实例化时作为参数代入到具体建造者中。
"""

4、建造者模式的缺点

#  1、“加工工艺”对用户不透明。(封装的两面性)

五、原型模式

1、图层

"""
	大家如果用过类似于Photoshop的平面设计软件,一定都知道图层的概念。图层概念的提出,使得设计、图形修改等操作更加便利。设计师既可以修改和绘制当前图像对象,又可以保留其它图像对象,逻辑清晰,且可以及时得到反馈。本节内容,将以图层为主角,介绍原型模式。
首先,设计一个图层对象。
"""

class simpleLayer:
    background = [0, 0, 0, 0]
    content = 'blank'

    def getContent(self):
        return self.content

    def getBackground(self):
        return self.background

    def paint(self, painting):
        self.content = painting

    def setParent(self, p):
        self.background[3] = p

    def fillBackground(self, back):
        self.background = back


#  在实际的实现中,图层实现会很复杂,这里仅介绍相关的设计模式,做了比较大的抽象,
#  用background表示背景的RGBA,简单用content表示内容,除了直接绘画,
#  还可以设置透明度。
# 新建图层,填充蓝底并画一只狗,可以简单表示如下:

if __name__ == '__main__':
    dog_layer = simpleLayer()
    dog_layer.paint('Dog')
    dog_layer.fillBackground([0, 0, 255, 0])
    print('Background:', dog_layer.getBackground())
    print('Painting:', dog_layer.getContent())



Background: [0, 0, 255, 0]
Painting: Dog

进程已结束,退出代码 0


"""
	接下来,如果需要再生成一个同样的图层,再填充同样的颜色,再画一只同样狗,该如何做呢?还是按照新建图层、填充背景、画的顺序么?或许你已经发现了,这里可以用复制的方法来实现,而复制(clone)这个动作,就是原型模式的精髓了。
	按照此思路,在图层类中新加入两个方法:clone和deep_clone
"""


from copy import copy, deepcopy
class simpleLayer:
    background=[0,0,0,0]
    content="blank"
    def getContent(self):
        return self.content
    def getBackgroud(self):
        return self.background
    def paint(self,painting):
        self.content=painting
    def setParent(self,p):
        self.background[3]=p
    def fillBackground(self,back):
        self.background=back
    def clone(self):
        return copy(self)
    def deep_clone(self):
        return deepcopy(self)
if  __name__=="__main__":
    dog_layer=simpleLayer()
    dog_layer.paint("Dog")
    dog_layer.fillBackground([0,0,255,0])
    print ("Background:",dog_layer.getBackgroud())
    print ("Painting:",dog_layer.getContent())
    another_dog_layer=dog_layer.clone()
    print "Background:", another_dog_layer.getBackgroud()
    print "Painting:", another_dog_layer.getContent()


打印结果如下:
Background: [0, 0, 255, 0]
Painting: Dog
Background: [0, 0, 255, 0]
Painting: Dog
    
    
    
    
"""
	clone和deep_clone有什么区别呢?大多数编程语言中,都会涉及到深拷贝和浅拷贝的问题,一般来说,浅拷贝会拷贝对象内容及其内容的引用或者子对象的引用,但不会拷贝引用的内容和子对象本身;而深拷贝不仅拷贝了对象和内容的引用,也会拷贝引用的内容。所以,一般深拷贝比浅拷贝复制得更加完全,但也更占资源(包括时间和空间资源)。举个例子,下面的场景,可以说明深拷贝和浅拷贝的区别。
"""
    
if  __name__=="__main__":
    dog_layer=simpleLayer()
    dog_layer.paint("Dog")
    dog_layer.fillBackground([0,0,255,0])
    print "Original Background:",dog_layer.getBackgroud()
    print "Original Painting:",dog_layer.getContent()
    another_dog_layer=dog_layer.clone()
    another_dog_layer.setParent(128)
    another_dog_layer.paint("Puppy")
    print "Original Background:", dog_layer.getBackgroud()
    print "Original Painting:", dog_layer.getContent()
    print "Copy Background:", another_dog_layer.getBackgroud()
    print "Copy Painting:", another_dog_layer.getContent()
  
打印结果如下:
Original Background: [0, 0, 255, 0]
Original Painting: Dog
Original Background: [0, 0, 255, 128]
Original Painting: Dog
Copy Background: [0, 0, 255, 128]
Copy Painting: Puppy

"""

浅拷贝后,直接对拷贝后引用(这里的数组)进行操作,原始对象中该引用的内容也会变动。如果将another_dog_layer=dog_layer.clone()换成another_dog_layer=dog_layer.deep_clone(),即把浅拷贝换成深拷贝,其如果如下:


Original Background: [0, 0, 255, 0]
Original Painting: Dog
Original Background: [0, 0, 255, 0]
Original Painting: Dog
Copy Background: [0, 0, 255, 128]
Copy Painting: Puppy


深拷贝后,其对象内的引用内容也被进行了复制。
"""

2、原型模式

#  原型模式定义如下:用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。
#  需要注意一点的是,进行clone操作后,新对象的构造函数没有被二次执行,新对象的内容是从内存里直接拷贝的。

在这里插入图片描述

3、优点

"""
1、性能极佳,直接拷贝比在内存里直接新建实例节省不少的资源;
2、简化对象创建,同时避免了构造函数的约束,不受构造函数的限制直接复制对象,是优点,也有隐患,这一点还是需要多留意一些。

使用场景:
1、对象在修改过后,需要复制多份的场景。如本例和其它一些涉及到复制、粘贴的场景;
2、需要优化资源的情况。如,需要在内存中创建非常多的实例,可以通过原型模式来减少资源消耗。此时,原型模式与工厂模式配合起来,不管在逻辑上还是结构上,都会达到不错的效果;
3、某些重复性的复杂工作不需要多次进行。如对于一个设备的访问权限,多个对象不用各申请一遍权限,由一个设备申请后,通过原型模式将权限交给可信赖的对象,既可以提升效率,又可以节约资源。
"""

4、缺点

"""
1、深拷贝和浅拷贝的使用需要事先考虑周到;
2、某些编程语言中,拷贝会影响到静态变量和静态函数的使用。
"""

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值