Python 设计模式:工厂模式、单例模式

1. 工厂模式

2. 单例模式

 

 

1. 工厂模式

1.1 初步设计

设计一个卖车的4S店,该怎样做呢?

 1 # 定义车类
 2 class Car:
 3 
 4     # 定义车的方法
 5     def move(self):
 6         print("车启动")
 7         
 8     def stop(self):
 9         print("停车")
10     
11     
12 # 定义一个销售车的店类
13 class CarStore:
14 
15     def order(self):
16         self.car = Car()
17         self.car.move()
18         self.car.stop()
19         
20 
21 # 进行购车
22 my_car = CarStore()
23 my_car.order()

上面的 4s 店,只能销售定义了的一种类型的车。如果这是个销售北京现代品牌的车,比如伊兰特、索纳塔等,该怎样做呢?

设计一个卖北京现代车的4S店

 1 # 定义伊兰特车类
 2 class YilanteCar(object):
 3 
 4     # 定义车的方法
 5     def move(self):
 6         print("---车在移动---")
 7 
 8     def stop(self):
 9         print("---停车---")
10 
11 # 定义索纳塔车类
12 class SuonataCar(object):
13 
14     # 定义车的方法
15     def move(self):
16         print("---车在移动---")
17 
18     def stop(self):
19         print("---停车---")
20 
21 # 定义一个销售北京现代车的店类
22 class CarStore(object):
23 
24     def order(self, typeName):
25         #根据客户的不同要求,生成不同的类型的车
26         if typeName == "伊兰特":
27             car = YilanteCar()
28         elif typeName == "索纳塔":
29             car = SuonataCar()
30         return car

这样做不太好,因为当北京现代又生产一种新类型的车时,又得在 CarStore 类中修改,有没有好的解决办法呢?

1.2 简单工厂模式

1)使用函数实现:

 1 # 定义伊兰特车类
 2 class YilanteCar(object):
 3 
 4     # 定义车的方法
 5     def move(self):
 6         print("---车在移动---")
 7 
 8     def stop(self):
 9         print("---停车---")
10 
11 # 定义索纳塔车类
12 class SuonataCar(object):
13 
14     # 定义车的方法
15     def move(self):
16         print("---车在移动---")
17 
18     def stop(self):
19         print("---停车---")
20 
21 # 用来生成具体的对象
22 def createCar(typeName):
23     if typeName == "伊兰特":
24         car = YilanteCar()
25     elif typeName == "索纳塔":
26         car = SuonataCar()
27     return car
28 
29 # 定义一个销售北京现代车的店类
30 class CarStore(object):
31 
32     def order(self, typeName):
33         # 让工厂根据类型,生产一辆汽车
34         car = createCar(typeName)
35         return car

2)使用类来实现:

 1 # 定义伊兰特车类
 2 class YilanteCar(object):
 3 
 4     # 定义车的方法
 5     def move(self):
 6         print("---车在移动---")
 7 
 8     def stop(self):
 9         print("---停车---")
10 
11 # 定义索纳塔车类
12 class SuonataCar(object):
13 
14     # 定义车的方法
15     def move(self):
16         print("---车在移动---")
17 
18     def stop(self):
19         print("---停车---")
20 
21 # 定义一个生产汽车的工厂,让其根据具体的订单生产车
22 class CarFactory(object):
23 
24     def createCar(self, typeName):
25         if typeName == "伊兰特":
26             car = YilanteCar()
27         elif typeName == "索纳塔":
28             car = SuonataCar()
29 
30         return car
31 
32 # 定义一个销售北京现代车的店类
33 class CarStore(object):
34 
35     def __init__(self):
36         #设置4s店的指定生产汽车的工厂
37         self.carFactory = CarFactory()
38 
39     def order(self, typeName):
40         # 让工厂根据类型,生产一辆汽车
41         car = self.carFactory.createCar(typeName)
42         return car

咋一看来,好像只是把生产环节重新创建了一个类,这确实比较像是一种编程习惯,此种解决方式被称作简单工厂模式。

工厂函数、工厂类对具体的生成环节进行了封装,这样有利于代码的后需扩展,即把功能划分的更具体,4s店只负责销售,汽车厂只负责制造。

1.3 工厂模式

多种品牌的汽车 4S 店

当买车时,有很多种品牌可以选择,比如北京现代、别克、凯迪拉克、特斯拉等,那么此时该怎样进行设计呢?

把以上代码复制一份显然会有冗余的重复代码,那么可以将汽车店共有的方法放在基类中,而子类负责实现各自不同的部分。

 1 # 所有车都有的基本功能
 2 class Car:
 3 
 4     def __init__(self, name):
 5         self.name = name
 6 
 7     def start(self):
 8         print("%s启动了" % self.name)
 9 
10     def stop(self):
11         print("%s停车了" % self.name)
12 
13 
14 class Suonata(Car):
15     pass
16 class Mingtu(Car):
17     pass
18 class Mini(Car):
19     pass
20 class Smart(Car):
21     pass
22 
23 
24 # 生产现代汽车的工厂
25 class ModernFactory:
26 
27     def createCarByType(self, type):
28         if type == '索纳塔':
29             return Suonata('索纳塔')
30         if type == '明图':
31             return Mingtu('明图')
32 
33 
34 # 生产宝马汽车的工厂
35 class BMWFactory:
36 
37     def createCarByType(self, type):
38         if type == 'Mini':
39             return Mini('Mini')
40         if type == 'Smart':
41             return Smart('Smart')
42 
43 
44 # 4S店 基类
45 class CarStore:
46 
47     # 提供接口,让子类自己根据需要实现
48     def select_car(self):
49         pass
50 
51     def order(self, type):
52         return self.select_car(type)
53         
54     # 4S店更多的公有功能
55     # def ...
56 
57 
58 # 现代汽车4S店
59 class ModernStore(CarStore):
60 
61     def select_car(self, type):
62         return ModernFactory().createCarByType(type)
63 
64 
65 # 宝马汽车4S店
66 class BmwStore(CarStore):
67 
68     def select_car(self, type):
69         return BMWFactory().createCarByType(type)
70 
71 
72 
73 modern_store = ModernStore()
74 modern_car = model_store.order("索纳塔")
75 modern_car.start()
76 modern_car.stop()
77 
78 bmw_store = BmwStore()
79 bmw = bmw_store.order("Smart")
80 bmw.start()
81 bmw.stop()
  • 最后来看看工厂方法模式的定义:定义了一个创建对象的接口(可以理解为函数),由子类决定要实例化的类是哪一个。工厂方法模式让类的实例化推迟到子类,抽象的 CarStore 提供了一个创建对象的方法 select_car,也叫作工厂方法。
  • 子类真正实现这个 select_car 方法创建出具体产品。创建者类选择了使用了哪个子类,就决定了实际创建的产品是什么。

 

2. 单例模式

什么是单例模式?确保某一个类只有一个实例,在实例化时自行向整个系统提供这个实例,这个类被称为单例类,单例模式是一种对象创建型模式。

举个常见的单例模式例子,我们日常使用的电脑上都有一个回收站,在整个操作系统中,回收站只能有一个实例,整个系统都使用这个唯一的实例,而且回收站自行提供自己的实例。因此回收站是单例模式的应用。

创建单例,保证只有 1 个对象

 1 class Singleton:
 2 
 3     __instance = None
 4     
 5     # 如果__instance没有被赋值过(即为None),
 6     # 那么就创建一个对象,并且赋值为这个对象的引用,保证下次调用这个方法时
 7     # 能够知道之前已经创建过对象了,这样就保证了只有1个对象
 8     # 注意,此处__new__()方法中的age与name既不是类属性也不是实例属性,虽然在创建对象时需要传参,但无实际作用
 9     def __new__(cls, age, name):
10         if not cls.__instance:
11             cls.__instance = object.__new__(cls)
12         return cls.__instance
13         
14 
15 xiaoming = Singleton(18, "xiaoming")
16 xiaodan = Singleton(18, "xiaodan")
17 # xiaoming与xiaodan实际为同一个对象
18 print(id(xiaoming))  # 46105504
19 print(id(xiaodan))  # 46105504  
20 
21 xiaoming.age = 19  # 给对象xiaoming添加属性
22 print(xiaodan.age)  # 19

创建单例,只执行 1 次 __init__() 方法

 1 class Singleton:
 2 
 3     __instance = None
 4     __first_init = False
 5     
 6     def __new__(cls, age, name):
 7         if not cls.__instance:
 8             cls.__instance = object.__new__(cls)
 9         return cls.__instance
10     
11     def __init__(self, age, name):
12        # 判断是否第一次执行 init 方法
13         if not Singleton.__first_init:
14             self.age = age
15             self.name = name
16             Singleton.__first_init = True
17     
18 
19 xiaoming = Singleton(18, "xiaoming")
20 xiaodan = Singleton(18, "xiaodan")
21 
22 print(id(xiaoming))  # 46105504
23 print(id(xiaodan))  # 46105504
24 
25 print(xiaoming.age)  # 18
26 print(xiaodan.age)  # 18
27 
28 xiaoming.age = 19  # 修改xiaoming对象的实例属性
29 print(xiaodan.age)  # 19

单例模式的线程安全问题

未加锁版的单例模式,在多线程下,可能会存在线程安全问题,即创建了多个实例。

 1 class Singleton:
 2 
 3     __instance = None
 4     # 如果__instance没有被赋值过(即为None),
 5     # 那么就创建一个对象,并且赋值为这个对象的引用,保证下次调用这个方法时
 6     # 能够知道之前已经创建过对象了,这样就保证了只有1个对象
 7 
 8     def __new__(cls):
 9         if not cls.__instance:  # 此处有可能发生多个线程同时判断了False,从而各自创建实例对象
10             cls.__instance = object.__new__(cls)
11         return cls.__instance

改进:DCL(Double Check Lock,双重检查锁)单例模式

此加锁版的单例模式,可以避免线程安全问题。

 1 class Singleton:
 2 
 3     __instance = None
 4     # 如果__instance没有被赋值过(即为None),
 5     # 那么就创建一个对象,并且赋值为这个对象的引用,保证下次调用这个方法时
 6     # 能够知道之前已经创建过对象了,这样就保证了只有1个对象
 7 
 8     def __new__(cls):
 9         if not cls.__instance:  # 此处的判断,多线程间可各自执行判断,无需争夺锁资源,因此耗时纳秒级别
10             lock.acquire():
11                 if not cls.__instance:  # 如果没有外层的if判断,则每次判断都需要各个线程先争夺锁,耗时在微秒级别
12                     cls.__instance = object.__new__(cls)
13                     lock.release()
14         return cls.__instance

 

posted @ 2020-02-20 22:00  Juno3550  阅读(245)  评论(0编辑  收藏  举报