- 参考自:
面向对象设计的 SOLID 原则
- 单一责任原则(Single Responsibility Principle, SRP):一个类或者一个方法只做一件事。
- 开放封闭原则(Open Closed Principle, OCP):对扩展开放,对修改关闭。换言之,一个类独立之后就不应该去修改它,而是以扩展的方式适应新需求。
- 里氏替换原则(Liskov Substitution Principle, LSP):所有基类出现的地方都可以用派生类替换而不会程序产生错误。
- 依赖倒置原则(Dependency Inversion Principle, DIP):高级模块不应该依赖低级模块,抽象不能依赖细节。
- 接口分离原则(Interface Segregation Principle, ISP):类不应该依赖不需要的接口。
设计模式总览
单例模式(Singleton)
概念
- 原理:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
- 优点:
- 全局只有一个实例,节省内存。
- 全局只有一个访问点,便于数据同步控制和共享访问。
- 单例可长驻内存,减少系统创建、销毁实例的开销。
- 缺点:
- 比较难扩展,除非修改单例类的源代码。
- 不能赋予单例太多职责,否则违反单一职责原则。
- 多线程下更容易引发锁竞争,成为性能瓶颈。
- 应用:
- 生成全局惟一的序列号;
- 访问全局复用的惟一资源,如磁盘、总线等;
- 单个对象占用的资源过多,如数据库等;
- 系统全局统一管理,如Windows下的Task Manager;
- 网站计数器。
- 分类:
- 懒汉式:只有第一次访问单例的时候,才会初始化单例。本身是非线程安全的,但可以采用并发控制维护线程安全。优点是第一次访问慢,缺点是并发控制影响性能。懒汉式用的比较少。
- 饿汉式:类一旦加载,就把单例初始化。天生就是线程安全的,不需要并发控制。优点是访问速度快,缺点是第一次访问前就实例化了,无意义地占用内存。饿汉式用的比较多。
- 难点:防反射攻击。无论是懒汉式还是饿汉式,只要有构造方法,也无论构造方法是公开的还是私有的,都可以通过反射机制调用构造方法创建新实例,所以防反射攻击的一般方法是在构造方法里判断单例是否已经初始化。
Java 实现
- 懒汉式:非线程安全
public class Singleton { |
- 饿汉式:线程安全
public class Singleton { |
- 懒汉式:方法锁,线程安全。锁竞争比较激烈,因为不管有没有实例化都要加锁。
public class Singleton { |
- 懒汉式:双重校验锁,线程安全。
- 第一次判断
uniqueInstance == null
是为了在已经实例化后直接返回单例,不会无意义地加锁。 - 第二次判断
uniqueInstance == null
是为了避免多个进程进入第一层if后,重复进行初始化,因为第一层if和synchronized之间不是临界区,所以可能有多个进程同时进入。 - volatile 关键字禁止指令重排,保证线程安全。因为正常情况下new方法是先初始化实例再分配地址,指令重排后可能没初始化就分配了地址,导致uniqueInstance不为空但属性值都未初始化。
- 第一次判断
public class Singleton { |
- 懒汉式:静态内部类,线程安全。使用静态内部类不需要加锁,性能比较好。
public class Singleton { |
- 防反射攻击的构造方法
public class Singleton { |
Python 实现
因为Python的多线程本身就是垃圾,所以就不讨论线程安全了。
使用模块:Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。
######## Singleton.py ############# |
- 使用装饰器:装饰器函数的字典里存储着它所标记的所有类的单例,当调用
a = A(x)
时,实际执行过程是a = Singleton(A)(x) = _singleton(x) = _instance[A]
。
def Singleton(cls): |
- 重写 init 或 new 函数:区别在于,new 函数负责创建实例,init 函数负责初始化实例,调用
s = Singleton()
时实际上是先调用 new 再调用 init,所以修改哪个都行。
######## 写法一 ############# |
简单工厂模式(Simple Factory)
概念
- 原理:定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
- 优点:
- 实现了责任分割,工厂类中的判断逻辑可以决定创建哪个产品类的实例,客户端不负责创建产品实例,而仅仅是消费产品。
- 客户端无须知道所创建的具体产品类的类名,只需要向工厂提供具体产品类的参数。
- 缺点:
- 工厂类集中了所有产品创建逻辑,一旦工厂类罢工,整个系统都会瘫痪。
- 系统扩展困难。一旦添加新产品就不得不修改工厂逻辑,破坏了开闭原则。
- 产品类型较多时,工厂逻辑过于复杂,不利于系统的维护。
- 适用场景:工厂类负责创建的对象比较少
Java 实现
public interface Product {} |
Python 实现
# 定义虚类。相当于 Java 的接口 |
工厂方法模式(Factory Method)
概念
- 原理:工厂方法模式是简单工厂模式的进一步抽象,让一个类的实例化延迟到其子工厂类。
- 优点:将创建对象的细节完全封装在具体工厂内部,在系统中加入新产品时,符合开闭原则。
- 缺点:系统中类的个数将成对增加,每个具体产品类都对应一个具体工厂类,增加了系统的复杂度。
- 适用场景:
- 日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。
- 数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。
- 设计一个连接服务器的框架,需要三个协议,”POP3”、”IMAP”、”HTTP”,可以把这三个作为产品类,共同实现一个接口。
Java 实现
public abstract class Factory { |
Python 实现
class Factory(metaclass=ABCMeta): |
抽象工厂模式(Abstract Factory)
概念
- 原理:抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形式,每个具体工厂可以创建一系列相关或相互依赖产品
- 优点:当一个产品族中的多个对象被设计成一起工作时,能够保证客户端始终只使用同一个产品族中的对象。同时,增加新的产品族很方便,无须修改已有系统,符合开闭原则。
- 缺点:增加新的产品等级结构麻烦,可能需要修改抽象层代码,违背了开闭原则。
- 适用场景:
- QQ 换皮肤,一整套一起换。
- 生成不同操作系统的程序。
Java 实现
public class AbstractProductA {} |
Python 实现
- 略
生成器/建造者模式(Builder)
概念
- 原理:封装了一个对象的构造过程,将复杂对象的构建过程与表示分离,使用相同的构建步骤作用于不同的子对象可以构建出不同表现形式的复杂对象。对于不太复杂的产品,可能只需要一个builder类就可以完成构建,如果产品过于复杂,可以先用一个builder类去生成产品的各个子部件,然后用director类将这些子部件组装成产品。
- 优点:
- 把对象的构造步骤封装在builder类中,使得客户不必知道产品内部的组成细节。
- 将构建代码和表示代码分开,便于对构建过程做精细控制。
- 缺点:难以应对分步骤构建的需求变动。
- 适用场景:需要生成的产品有复杂的内部结构和属性间的相互依赖,具有稳定的构建顺序。
Java 实现
- 略
Python 实现
######## 模拟快餐店点餐 ########## |
原型模式(Prototype)
概念
- 原理:通过复制一个已经存在的实例来获得一个新的实例,把对象的创建逻辑封装在它自身里,有时也能减小创建此类实例带来的开销,被复制的实例就是所谓的原型。有深拷贝和浅拷贝两种实现方式。
- 优点:在创建复杂或耗时的实例时,一定程度上减小了开销。
- 缺点:原型类需要配置一个克隆方法,并且这个克隆方法需要对类的功能进行整体考虑。
- 适用场景:
- 为了避免创建一个与产品类层次平行的工厂类层次时。
- 当实例化的类是在运行时刻指定时。
- 当一个系统应该独立于他的产品的创建、构成和表示时。也就是产品自己实现实例的创建。
Java 实现
public abstract class Prototype { |
Python 实现
from copy import copy, deepcopy |
责任链模式(Chain Of Responsibility)
概念
- 原理:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止。
- 优点:
- 降低了请求发出者和请求处理者之间的耦合。
- 增强了对象指派职责的灵活性,通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
- 简化了对象,使得对象不需要知道链的结构。
- 增加新的请求处理类很方便。
- 缺点:
- 责任链过长会出现性能问题。
- 不能保证请求一定被接收。
- 另一方面,如果一个情求没有被正确处理也就是说不存在一个可以处理该请求的命令接收者而反复执行。
- 适用场景:有多个对象可以处理一个请求,哪个对象处理该请求会在运行时刻自动确定。
Java 实现
public abstract class Handler { |
Python 实现
class Handler(): |
命令模式(Command)
概念
- 原理:将请求封装成对象,将其作为命令调用者和接收者的中介,而抽象出来的命令对象又使得能够对一系列请求进行特殊操作。
- 优点:
- 降低对象之间的耦合度。
- 新的命令可以很容易地加入到系统中。
- 可以比较容易地设计一个组合命令。
- 缺点:可能会导致某些系统有过多的具体命令类,影响系统性能。
- 适用场景:
- 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
- 在不同的时刻指定、排列和执行请求。
- 系统需要将一组操作组合在一起,即支持宏命令。
- GUI 中每一个按钮都是一条命令。
- 模拟 CMD。
Java 实现
// 模拟灯光遥控器。命令的发起者是人,接受者是灯,而中间负责调度和执行的是 Invoker 类。 |
Python 实现
class LightOnCommand(): |
解释器模式(Interpreter)
概念
- 原理:给定一个语言,定义它的文法的一种表示(分为终结符表达式和非终结符表达式),并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
- 优点:易于改变和扩展文法,可以方便地实现一个简单的语言。
- 缺点:
- 对于复杂文法难以维护,执行效率较低。
- 可利用场景比较少。
- 解释器模式会引起类膨胀。
- 解释器模式采用递归调用方法。
- 适用场景:鸡肋。
Java 实现
- 略
Python 实现
- 略
迭代器模式(Iterator)
- 原理:提供一种顺序访问聚合对象元素的方法,并且不暴露聚合对象的内部表示。要使得聚合对象保持整洁和优雅,而不是说令聚合对象内部包含着各种遍历的方法,因此要将遍历的方法从聚合对象的指责中分离出来,按照不同的遍历需求分别封装成一个个专门遍历聚合对象内部数据的迭代器。
- 优点:
- 在同一个聚合对象上可以定义多种遍历方式 简化了聚合类。
- 由于引入了抽象层,增加新的聚合类和迭代器类都很方便,无须修改原有代码,符合开闭原则。
- 缺点:
- 在增加新的聚合类时需要对应地增加新的迭代器类,类的个数成对增加。
- 抽象迭代器的设计难度较大,需要充分考虑到系统将来的扩展。
- 解释器模式会引起类膨胀。
- 解释器模式采用递归调用方法。
- 适用场景:需要遍历内部数据的对象都可以使用。
Java 实现
public interface Aggregate { |
Python 实现
class Aggregate(): |
中介者模式(Mediator)
概念
- 原理:用一个中介对象封装一系列的对象交互。中介者使各对象不需要显式地互相作用,从而使其耦合松散,并可以独立地改变它们之间的交互。很重要的一点就是中介者模式可以使得对象之间的关系数量急剧减少。
- 优点:
- 降低了类的复杂度,将一对多转化成了一对一。
- 各个类之间的解耦。
- 符合迪米特原则(一个类对于其他类知道的越少越好)。
- 缺点:中介者会庞大,变得复杂难以维护。
- 适用场景:用于一组对象以定义良好但是复杂的方式进行通信的场合,以及想定制一个分布在多个类中的行为,而又不想生成太多的子类的场合。设计类图时,出现了网状结构时,可以考虑将类图设计成星型结构,这样就可以使用中介者模式了。如机场调度系统、路由系统,著名的MVC框架中,其中的C就是M和V的中介者。
Java 实现
- 需要配合的所有 ConcreteColleague 实例都是 ConcreteMediator 的实例的属性,ConcreteMediator 负责调度这些属性对象。
Python 实现
备忘录模式(Memento)
概念
- 原理:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原来保存的状态。(就是备份呗)
- 优点:
- 给用户提供了一种状态恢复的实现机制。
- 实现了信息的封装,用户不需要关心状态的保存细节。
- 缺点:额外存储备忘录对象,资源消耗大。
- 适用场景:实现撤销操作或事务回滚。
Java 实现
// 模拟保存游戏进度 |
Python 实现
class GameCharacter(): |
观察者模式(Observer)
概念
- 原理:定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象都得到通知并被自动更新。发生改变的对象称为观察目标(subject),被通知的对象称为观察者(observer)。一个观察目标可以对应多个观察者。
- 优点:
- 实现了表示层和数据逻辑层的分离,在观察目标和观察者之间建立一个抽象的耦合。
- 支持广播通信,简化了一对多系统设计的难度,符合开闭原则,增加新的观察者或观察目标很方便。
- 缺点:
- 如果一个观察目标有很多的观察者,通知过程会十分耗时。
- 如果观察者和观察目标之间存在循环依赖,可能导致系统崩溃。
- 观察者无法知道观察目标是怎么发生变化的,仅仅只是知道其发生了变化。
- 适用场景:
- 一个抽象模型有两个方面,其中一个方面依赖于另一个方面,即一种单向依赖的场景。
- 一个对象的改变将导致其他某些对象发生改变,而无需知道具体哪些对象将发生改变,可以降低对象之间的耦合度。
- 可以使用观察者模式创建一种链式触发机制,A对象的行为将影响B对象,B对象的行为将影响C对象。
Java 实现
// Java 内置了观察者模式的类和接口实现,封装了订阅、取消订阅、通知等操作。 |
Python 实现
# 模拟火灾报警器。报警器、洒水器、拨号器是观察者,烟雾传感器是观察目标。 |
状态模式(State)
概念
- 原理:允许一个对象在其内部状态改变时改变它的行为,即不同的状态对应了不同的行为,一个对象的行为取决于动态变化的状态。
- 优点:
- 封装了转换规则,可以对状态转换代码进行集中管理,而不是分散在一个个业务方法中。
- 将所有与某个状态有关的行为放到一个类中,方便增加新的状态,因为改变状态就自动改变了行为。
- 允许状态转换逻辑与状态对象合成一体,而不是提供一个巨大的条件语句块。
- 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
- 缺点:
- 增加了系统中类和对象的个数,导致系统运行开销增大。
- 状态模式的结构与实现都较为复杂,使用不当将导致程序结构和代码的混乱。
- 对开闭原则的支持不太好,增加新的状态类需要修改负责状态转换的源代码,否则无法转换到新增状态,而且修改某个状态类的行为也需要修改对应类的源代码。
- 适用场景:
- 行为依赖于状态,优化代码中大量与对象状态有关的条件语句。
- 电梯、红绿灯、网上订单、文件审批等。
Java 实现
// 模拟宾馆的状态转换,有已预订、已入住、空闲三种状态。 |
Python 实现
- 略~
策略模式(Strategy)
概念
- 原理:定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法类可以独立于使用它的对象,提供了一种可插入式算法的实现方案,不需要将所有算法都硬编码到对象内部。策略模式和状态模式本质上是相同的,就看怎么理解状态转移和策略选择这两种行为的细微差别了。
- 优点:
- 提供了对开闭原则的完美支持,可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。
- 提供了管理相关的算法族的办法。
- 提供了一种可以替换继承关系的办法 可以避免多重条件选择语句。
- 提供了一种算法的复用机制,不同的环境类可以方便地复用策略类。
- 缺点:
- 策略类会增多。
- 所有策略类都需要对外暴露。
- 适用场景:一个系统需要动态地在几种算法中选择一种。
Java 实现
public interface Strategy { |
Python 实现
- 略~
模板方法模式(Template Method)
概念
- 原理:定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类不改变一个算法的结构即可重定义该算法的某些特定步骤,模板方法关注这样的一类行为,该类行为在执行过程中拥有大致相同的动作次序,只是动作在实现的具体细节上有所差异。
- 优点:
- 封装不变部分,扩展可变部分。
- 提取公共代码,便于维护。
- 行为框架由父类控制,子类按需各自实现。
- 缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
- 适用场景:有多个子类共有的方法,且逻辑相同。
Java 实现
// 模拟泡茶和泡咖啡的流程 |
Python 实现
- 略~
访问者模式(Visitor)
概念
- 原理:访问者封装了一些作用于某种数据结构中的各元素的操作,对元素的具体操作可以随着访问者改变而改变,实现了数据结构与数据操作的分离。
- 优点:
- 符合单一指责,封装在访问者中的操作必定是与元素类本身关系不大且是易变的操作。
- 扩展性好,因为被封装的操作通常都是易变的,所以可以在不改变元素类本身的前提下,实现对操作的扩展,元素类也可以通过接受不同的访问者来支持不同操作。
- 缺点:
- 具体元素对访问者公布细节,违反了迪米特原则。
- 具体元素变更比较困难,增加新的元素可能需要在每一个具体访问者类中增加相应的具体操作,违背了开闭原则。
- 违反了依赖倒置原则,依赖了具体类,没有依赖抽象。
- 适用场景:对象类型少但支持的操作很丰富,需要避免让这些操作污染对象的类。
Java 实现
public interface ComputerPart { |
Python 实现
- 略~
空对象模式(Null)
概念
- 原理:用返回空对象取代返回 NULL ,既可以避免抛出空指针异常,又可以在数据不可用的时候提供默认的行为。
- 优点:略
- 缺点:略
- 适用场景:略
Java 实现
public abstract class AbstractCustomer { |
Python 实现
- 略~
适配器模式(Adapter)
概念
- 原理:为了解决接口不兼容的问题引进的一种接口兼容机制,通过提供一种适配器类将第三方提供的接口转换为客户希望的接口。
- 优点:
- 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构 增加了类的透明性和复用性。
- 灵活性和扩展性非常好。
- 缺点:
- 过多地使用适配器会让系统非常零乱,不易整体进行把握。
- 由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。
- 适用场景:
- 系统需要使用现有的类,而此类的接口不符合系统的需要。
- 美国电器 110V,中国 220V,就要有一个适配器将 110V 转化为 220V。
- JAVA JDK 1.1 提供了 Enumeration 接口,而在 1.2 中提供了 Iterator 接口,想要使用 1.2 的 JDK,则要将以前系统的 Enumeration 接口转化为 Iterator 接口。
- 在 LINUX 上运行 WINDOWS 程序。
- JAVA 中的 jdbc。
Java 实现
public interface MediaPlayer { |
Python 实现
from abc import abstractmethod,ABCMeta |
桥接模式(Bridge)
概念
- 原理:有些类在功能设计上要求自身包含两个或两个以上变化的因素,比如对于一杯咖啡,咖啡杯的大小和是否加奶为两个变化因素,使得这杯咖啡在这两个维度上发生变化。桥接模式是将抽象部分与它的实现部分解耦,使得两者都能够独立变化适应业务需求,两个部分中的任何一部分发生变化时都不会影响对方。
- 优点:
- 分离了抽象接口与其实现部分,可以取代多层继承方案,将类之间的静态继承关系转换为动态的对象组合关系,极大地减少了子类的个数。
- 提高了系统的可扩展性,在两个变化维度中任意扩展一个维度,不需要修改原有系统,符合开闭原则。
- 缺点:增加系统的理解与设计难度,由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计与编程。
- 适用场景:
- 如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
- 对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
- 一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
Java 实现
- 略~
Python 实现
# 用不同的笔画不同的图形,笔和图形是相互独立的,在基类之间建立关联后,就可以用对象组合的方式实现笔和图形的各种组合,而不需要让笔去继承所有图形类。 |
组合模式(Composite)
概念
- 原理:将对象组合成树形结构以表示部分和整体的层次结构,使得用户对单个对象和组合对象的使用具有一致性。主要用来处理具有容器特征的对象,它们即充当对象又可以作为容器包含其他多个对象。
- 优点:对节点增删和调用非常自由和方便。
- 缺点:在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。
- 适用场景:
- 希望把对象表示分成部分-整体层次结构,或希望用户忽略组合对象与单个对象的不同。
Java 实现
public class Employee { |
Python 实现
- 略~
装饰器模式(Decorator)
概念
- 原理:动态地给一个对象增加一些额外的职责。就扩展功能而言,装饰模式提供了一种比使用子类更加灵活的替代方案,因为只针对某个对象而不是对象所属的类。
- 优点:
- 装饰模式比继承更加灵活,不会导致类的个数急剧增加。
- 可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的具体装饰类,从而实现不同的行为。
- 可以对一个对象进行多次装饰。
- 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,且原有类库代码无须改变,符合开闭原则。
- 缺点:
- 多层装饰比较复杂。
- 使用装饰模式进行系统设计时将产生很多小对象,大量小对象的产生势必会占用更多的系统资源。
- 适用场景:代替继承,更灵活地增加和删除功能。
Java 实现
public interface Shape { |
Python 实现
- 略~
外观模式(Facade)
概念
- 原理:外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,从而降低客户端与子系统的耦合度。其实就是高度封装。
- 优点:
- 对客户屏蔽子系统组件,减少了客户处理的对象数目并使得子系统使用起来更加容易,实现了子系统与客户之间的松耦合关系。
- 降低了大型软件系统中的编译依赖性,简化了系统在不同平台之间的移植过程。
- 缺点:不能很好地限制客户使用子系统类,而且在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了开闭原则。
- 适用场景:为一个复杂子系统提供一个简单接口。
Java 实现
public class SubSystem { |
Python 实现
- 略~
享元模式(Flyweight)
概念
- 原理:运用共享技术有效地支持大量细粒度对象的复用。
- 优点:可以减少内存中对象的数量,使得相同或者相似的对象在内存中只保存一份,从而可以节约系统资源,提高系统性能。
- 缺点:
- 需要分离出内部状态和外部状态,使得系统变得复杂。
- 为了使对象可以共享,需要将享元对象的部分状态外部化,而读取外部状态将使得运行时间变长。
- 适用场景:一个系统有大量相同或者相似的对象,造成内存的大量耗费,同时对象的大部分状态都可以外部化。
Java 实现
public interface Shape { |
Python 实现
- 略~
代理模式(Proxy)
概念
- 原理:引入一个代理对象,在客户端对象和目标对象之间起到中介的作用,负责去掉客户不能看到的内容和服务或者增添客户需要的额外的新服务。
- 优点:
- 能够协调调用者和被调用者,在一定程度上降低了系统的耦合度。
- 增加和更换代理类无须修改源代码,符合开闭原则,系统具有较好的灵活性和可扩展性。
- 缺点:
- 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
- 实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
- 适用场景:
- 当客户端对象需要访问远程主机中的对象时可以使用远程代理。
- 当需要用一个消耗资源较少的对象来代表一个消耗资源较多的对象,从而降低系统开销、缩短运行时间时可以使用虚拟代理。
- 当需要为某一个被频繁访问的操作结果提供一个临时存储空间,以供多个客户端共享访问这些结果时可以使用缓冲代理。
- 当需要控制对一个对象的访问,为不同用户提供不同级别的访问权限时可以使用保护代理。
- 当需要为一个对象的访问提供一些额外的操作时可以使用智能引用代理。
Java 实现
// JDK 自带的动态代理 |
Python 实现
- 略~