设计模式大概分为 23 种,分三大类:
- 创建型模式 (Creational Patterns)
- 结构型模式 (Structural Patterns)
- 行为型模式 (Behavioral Patterns)
创建型模式
创建型模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建那些对象时更加灵活。
- 工厂模式 (Factory Pattern)
- 抽象工厂模式 (Abstract Factory Pattern)
- 单例模式 (Singleton Pattern)
- 创建者模式 (Builder Pattern)
- 原型模式 (Prototype Pattern)
简单工厂模式
简单工厂模式不是 23 种设计模式里的一种,一般用于小项目或具体产品很少扩展的情况。它由三种角色组成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
|
from abc import ABCMeta, abstractmethod
class Car(metaclass=ABCMeta): """Abstract product.""" @abstractmethod def price(self): pass
class Bmw(Car): """Implemented product."""
def price(self): return '$100,000'
class Byd(Car): """Implemented product"""
def price(self): return '$10,000'
class Factory(object): """Factory""" def produce(self, car_type): if car_type == 'bmw': return Bmw() elif car_type == 'byd': return Byd() else: return None
class Client(object): def main(self, *args, **kws): Factory().produce('bmw').prince() Factory().produce('byd').prince()
|
简单工厂模式实现了产品类与客户端分离,但当用户需要添加更多产品的时候,就要修改工厂类的代码了,工厂类并不符合 OOP 开放封闭原则。
工厂模式
意图:定义一个创建对象的接口,让其子类自己决定实例化哪个工厂类,工厂模式使其创建过程延迟到子类进行。
主要解决:接口选择的问题。
优点:扩展性高,符合开闭原则。
缺点:每增加一个产品,都要增加一个具体产品类和具体工厂类,使得系统中类的个数不断增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。
角色:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
|
import abc
class Car(classmeta=abc.ABCMeta): @abc.abstractmethod def price(self): pass
class Bmw(Car): def price(self): return '$10,000'
class Byd(Car): def price(self): return '$1,000'
class Factory(classmeta=abc.ABCMeta): @abc.abstractmethod def produce(self): pass
class BmwFactory(Factory): def produce(self): return Bmw()
class BydFactory(Factory): def produce(self): return Byd()
class Client(object): def main(self, *args, **kws): bmw = BmwFactory().produce() byd = BydFactory().produce()
|
抽象工厂模式
意图:创建一系列相关或相互依赖产品 (产品族)。当系统中的产品有多于一个的产品族,而系统只消费其中某一族的产品的时候。
主要解决:接口选择的问题。
优点:当客户端需要使用某一产品族的产品的时候,直接调用具体产品类接口,使用非常方便。
缺点:产品族扩展相对麻烦。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
|
import abc
class Mouse(metaclass=abc.ABCMeta): @abc.abstractmethod def price(self): pass
class DellMouse(Mouse): def price(self): return '$10'
class HpMouse(Mouse): def price(self): return '$15'
class Keyboard(metaclass=abc.ABCMeta): @abc.abstractmethod def price(self): pass
class DellKeyboard(Keyboard): def price(self): return '$100'
class HpKeyboard(Keyboard): def price(self): return '$150'
class Factory(metaclass=abc.ABCMeta): @abc.abstractmethod def create_mouse(self): pass
@abc.abstractmethod def create_keyboard(self):
class DellFactory(Factory): def create_mouse(self): return DellMouse()
def create_keyboard(self): return DellKeyboard()
class HpFactory(Factory): def create_mouse(self): return HpMouse()
def create_keyboard(self): return HpKeyboard()
class client(object):
def main(self): hp = HpFactory() hp_mouse = hp.create_mouse() hp_keyboard = hp.create_keyboard() dell = DellFactory() dell_mouse = dell.create_mouse() dell_keyboard = dell.create_keyboard()
|
单例模式
意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
主要解决:一个全局使用的类频繁地创建与销毁。
优点:在内存中只有一个实例,减少了内存的开销,同时避免了对资源的多重占用 (如写 文件操作)。
缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎样实例化。
使用场景:
- 要求生产唯一序列号。
- WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
- 创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
class Singleton(object): def __new__(cls, *args, **kwargs): if not hasattr(cls, '_instance'): cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs) return cls._instance
class SingletonBase(type): def __init__(self, *args, **kwargs): _instance = None super().__init__(self, *args, **kwargs)
def __call__(self, *args, **kwargs): if not self._instance: self._instance = super().__call__(self, *args, **kwargs) return self._instance
class Singleton(metaclass=SingletonBase): pass
|
创造者模式
意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
主要解决:在软件系统中,系统由若干部件组完,这些部件不变,但是组合方式经常变化。
何时使用:一些基本部件不变,但其组合经常变化的时候。
角色:
- 产品类
- 抽象建造者
- 具体建造者
- 指挥者 (director)
优点:
- 客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品。
- 每一个具体建造者都相对独立,而与其它的具体建造者无关,因此可以很方便地替换具体建造者或新增具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。
- 可以更加精密地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
- 增加新的具体建造者无需修改原有类库的代码,指挥者类针对抽象建造者类编程,而不是具体建造者类,符合依赖倒置原则。
缺点:
- 产品之间差异性很大的情况:建造者模式所创建的产品类一般具有较多的共同点,其组成部分相似,如果产品之间的差异很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
- 产品内部变化很复杂的情况:如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
import abc
class Meal(object): """meal product class""" food = None drink = None
class MealBuilder(metaclass=abc.ABCMeta): """Abstract builder"""
def __init__(self): self.meal = Meal()
@abc.abstractmethod def add_food(self): pass
@abc.abstractmethod def add_drink(self): pass
def get_meal(self): return self.meal
class MealA(MealBuilder): """Implement builder"""
def add_food(self): self.meal.food = 'childken burger'
def add_drink(self): self.meal.drink = 'coke'
class MealB(MealBuilder): """Implement builder"""
def add_food(self): self.meal.food = 'veg burger'
def add_drink(self): self.meal.drink = 'pepsi'
class Waiter(object): """director""" def create(self, meal): meal.add_food() meal.add_drink() return meal.get_meal()
class Client(object): def main(self): a = MealA() meal_a = Waiter(a).get_meal() b = MealB() meal_b = Waiter(b).get_meal()
|
近期评论