分类
创建型:单例模式、简单工厂模式、工厂方法模式、抽象工厂模式
结构型:代理模式
行为型:观察者模式
介绍
单例模式
**定义:**保证一个类仅有一个实例,并提供一个访问它的全局访问点。
结构图:
优点:
- 实现了对唯一实例访问的可控
- 对于一些需要频繁创建和销毁的对象来说可以提高系统的性能
缺点:
- 不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
- 没有抽象层,不利于拓展
- 职责过重,违反单一职责原则
使用场景:
- 资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件(一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加),应用配置。
- 控制资源的情况下,方便资源之间的互相通信。如线程池等。
观察者模式
**定义:**定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
结构:
Subject
:抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。ConcreteSubject
:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。Observer
:抽象观察者,是观察者者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。ConcrereObserver
:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。
使用场景:
- 关联行为场景,需要注意的是,关联行为是可拆分的,而不是“组合”关系。
- 事件多级触发场景。
- 跨系统的消息交换场景,如消息队列、事件总线的处理机制。
**优点:**解除耦合,让耦合的双方都依赖于抽象,从而使得各自的变换都不会影响另一边的变换。
缺点:在应用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且在Java中消息的通知一般是顺序执行,那么一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步实现。
代理模式
**定义:**为其他对象提供一种代理以控制这个对象的访问。(代购、打官司)
结构:
- Subject:抽象主题类,声明真实主题与代理的共同接口方法。
- RealSubject:真实主题类,定义了代理所表示的真实对象,客户端通过代理类间接的调用真实主题类的方法。
- ProxySubject:代理类,持有对真实主题类的引用,在其所实现的接口方法中调用真实主题类中相应的接口方法执行。
- Client:客户端类。
**实现:**代理类包含了真实主题类(被代理者),最终调用的都是真实主题类(被代理者)实现的方法
类型:
- 远程代理:为一个对象在不同的地址空间提供局部代表,这样系统可以将Server部分的事项隐藏。
- 虚拟代理:使用一个代理对象表示一个十分耗资源的对象并在真正需要时才创建。
- 安全代理:用来控制真实对象访问时的权限。
- 智能指引:当调用真实的对象时,代理处理另外一些事,比如计算真实对象的引用计数,当该对象没有引用时,可以自动释放它;或者访问一个实际对象时,检查是否已经能够锁定它,以确保其他对象不能改变它。
**使用场景:**无法或者不想直接访问某个对象时可以通过一个代理对象来间接的访问。
简单工厂模式
**定义:**定义一个类用来负责创建其他类的实例,被创建的实例通常都具有共同的父类
结构:
优点:
- 使用户根据参数获得对应的类实例,避免了直接实例化类,降低了耦合性。
缺点:
- 工厂类集中了所有实例(产品)的创建逻辑,一旦这个工厂不能正常工作,整个系统都会受到影响;
- 违背“开放 - 关闭原则”,一旦添加新产品就不得不修改工厂类的逻辑,这样就会造成工厂逻辑过于复杂。
- 简单工厂模式由于使用了静态工厂方法,静态方法不能被继承和重写,会造成工厂角色无法形成基于继承的等级结构。
使用场景:
- 工厂类负责创建的对象比较少。
- 客户只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心。
工厂方法模式
**定义:**定义一个用于创建对象的接口,让子类决定实例化哪一个类,使一个类的实例化延迟到其子类
结构:
优点:
- 更符合开-闭原则 ,新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可
- 符合单一职责原则 ,每个具体工厂类只负责创建对应的产品
- 不使用静态工厂方法,可以形成基于继承的等级结构
缺点:
- 添加新产品时,除了增加新产品类外,还要提供与之对应的具体工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度;同时,有更多的类需要编译和运行,会给系统带来一些额外的开销;
- 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
- 虽然保证了工厂方法内的对修改关闭,但对于使用工厂方法的类,如果要更换另外一种产品,仍然需要修改实例化的具体工厂类;
- 一个具体工厂只能创建一种具体产品
使用场景:
- 当一个类不知道它所需要的对象的类时。在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可;
- 当一个类希望通过其子类来指定创建对象时。在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。
- 将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。
抽象工厂模式
**定义:**提供一个创建一系列相关或者相互依赖对象的接口,则无需指定他们具体的类
结构:
**优点:**具体类的创建实例过程与客户端分离,客户端通过工厂的抽象接口操纵实例,客户端并不知道具体的实现是谁。
**缺点:**如果增加新的产品族则也需要修改抽象工厂和所有的具体工厂。
使用场景:
- 一个系统不依赖于产品线实例如何被创建、组合和表达的细节。
- 系统中有多于一个的产品线,而每次只使用其中某一产品线。
- 一个产品线(或是一组没有任何关系的对象)拥有相同的约束。
**注意:**当产品只有一个的时候,抽象工厂模式即变成工厂模式,当工厂模式的产品变成多个时,工厂模式即变成抽象工厂模式
策略模式
动机:
- 完成一项任务,往往可以有多种不同的方式,每一种方式称为一个策略,我们可以根据环境或者条件的不同选择不同的策略来完成该项任务。
- 在软件开发中也常常遇到类似的情况,实现某一个功能有多个途径,此时可以使用一种设计模式来使得系统可以灵活地选择解决途径,也能够方便地增加新的解决途径。
**定义:**定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。
UML图:
Context
: 环境类Strategy
: 抽象策略类ConcreteStrategy
: 具体策略类
状态模式
**定义:**允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。对象的行为依赖于它的状态,并且可以根据它的状态改变而改变它的相关行为。
UML图:
-
Context: 环境类
-
State: 抽象状态类
-
ConcreteState: 具体状态类
观察者模式
**定义:**定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
UML图:
中介者模式
**意图:**用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
**主要解决:**对象与对象之间存在大量的关联关系,这样势必会导致系统的结构变得很复杂,同时若一个对象发生改变,我们也需要跟踪与之相关联的对象,同时做出相应的处理。
**何时使用:**多个类相互耦合,形成了网状结构。
**如何解决:**将上述网状结构分离为星型结构。
**实现:**我们通过聊天室实例来演示中介者模式。实例中,多个用户可以向聊天室发送消息,聊天室向所有的用户显示消息。我们将创建两个类 ChatRoom 和 User。User 对象使用 ChatRoom 方法来分享他们的消息。
适配器模式
**意图:**将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
**主要解决:**主要解决在软件系统中,常常要将一些"现存的对象"放到新的环境中,而新环境要求的接口是现对象不能满足的。
桥接模式
**意图:**将抽象部分与实现部分分离,使它们都可以独立的变化。
**主要解决:**在有多种可能会变化的情况下,用继承会造成类爆炸问题,扩展起来不灵活。
装饰器模式
**意图:**动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
**主要解决:**一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。
**何时使用:**在不想增加很多子类的情况下扩展类。
代理模式
**定义:**在某些情况下,一个客户不想或者不能直接引用一个对 象,此时可以通过一个称之为“代理”的第三者来实现 间接引用。代理对象可以在客户端和目标对象之间起到 中介的作用,并且可以通过代理对象去掉客户不能看到 的内容和服务或者添加客户需要的额外服务。
UML图: