Java 23种设计模式
23种设计模式
1.单例模式
- 饿汉模式(线程不安全,速度快,浪费资源多)
- 懒汉模式(线程不安全,第一次加载较慢)
- 双重检测(加锁,线程安全,第一次加载较慢)
- 静态方法
2.工厂模式
定义一个用于创建爱你对象的接口,让子类决定实例化哪一个类,是一个类的实例化延迟到其子类
3.抽象工厂模式
提供一个创建乙烯类相关或者相互依赖对象的接口,而无需指定他们具体的类
4.建造者模式
使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式
解决的问题:
- 用户只需要给出指定复杂对象的类型和内容;
- 建造者模式负责按顺序创建复杂对象(把内部的建造过程和细节隐藏起来)
-
Product(产品角色): 一个具体的产品对象 (指出它的部件)
-
Builder(抽象建造者): 创建一个Product对象的各个部件指定的抽象接口 (定义抽象动作,具体实现未知)
-
ConcreteBuilder(具体建造者): 实现抽象接口,构建和装配各个部件 (定义具体做什么)
-
Director(指挥者): 构建一个使用Builder接口的对象。它主要是用于创建一个复杂的对象。它主要有两个作用,
一:隔离了客户与对象的生产过程
二:负责控制产品对象的生产过程。
模式讲解:
- 指挥者(Director)直接和客户(Client)进行需求沟通;
- 沟通后指挥者将客户创建产品的需求划分为各个部件的建造请求(Builder);
- 将各个部件的建造请求委派到具体的建造者(ConcreteBuilder);
- 各个具体建造者负责进行产品部件的构建;
- 最终构建成具体产品(Product)。
- 电脑城老板(Diretor)和小成(Client)进行需求沟通
- 了解需求后,电脑城老板将小成需要的主机划分为各个部件(Builder)的建造请求(CPU、主板blabla)
- 指挥装机人员(ConcreteBuilder)去构建组件;
- 组装成电脑(Product)
5.原型模式
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
**浅拷贝:**使用一个已知实例对新创建实例的成员变量逐个赋值(传递引用,不能复制实例)
**深拷贝:**当一个类的拷贝构造方法,不仅要复制对象的所有非引用成员变量,还要引用类型的成员变量创建新的实例,并且初始化为形式参数的实例值(对象内部的引用均复制,它是创建一个新的实例,并且复制实例)
**主要解决:**在运行期建立和删除原型。
何时使用:
- 如果创建新对象成本较大,我们可以利用已有的对象进行复制来获得。
- 如果系统要保存对象的状态,而对象的状态变化很小,或者对象本身占内存不大的时候,也可以使用原型模式配合备忘录模式来应用。相反,如果对象的状态变化很大,或者对象占用的内存很大,那么采用状态模式会比原型模式更好。
- 需要避免使用分层次的工厂类来创建分层次的对象,并且类的实例对象只有一个或很少的几个组合状态,通过复制原型对象得到新实例可能比使用构造函数创建一个新实例更加方便
模式构成
- Prototype:抽象原型类。声明克隆自身的接口。
- ConcretePrototype:具体原型类。实现克隆的具体操作。
- Client:客户类。让一个原型克隆自身,从而获得一个新的对象。
模式总结
- 原型模式向客户隐藏了创建对象的复杂性。客户只需要知道要创建对象的类型,然后通过请求就可以获得和该对象一模一样的新对象,无须知道具体的创建过程。
- 克隆分为浅克隆和深克隆两种。
6.适配者模式
将一个类的接口转换成客户希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作(直白点就是转接器)
模式构成
- **Target(目标抽象类):**目标抽象类定义客户所需的接口,可以是一个抽象类或接口,也可以是具体类。
- **Adapter(适配器类):**它可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配
- **Adaptee(适配者类):**适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类包好了客户希望的业务方法
7.桥接模式
桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化
模式构成
- **实现化(Implementor)角色:**定义实现化角色的接口,供扩展抽象化角色调用。
- **Abstraction(抽象化对象):**定义抽象类,并包含一个对实现化对象的引用
- **扩展抽象化(Refined Abstraction)角色:**是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
- **具体实现化(Concrete Implementor)角色:**给出实现化角色接口的具体实现。
8.组合模式
又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次
模式构成
- **Component(抽象构件):**它可以是接口或抽象类,为叶子构件和容器构件对象声明接口,在该角色中可以包含所有子类共有行为的声明和实现。在抽象构件中定义了访问及管理它的子构件的方法,如增加子构件、删除子构件、获取子构件等。
- **Leaf(叶子构件):**它在组合结构中表示叶子节点对象,叶子节点没有子节点,它实现了在抽象构件中定义的行为。
- **Composite(容器构件):**表示容器节点对象,容器节点包含子节点,其子节点可以是叶子节点,也可以是容器节点,它提供一个集合用于存储子节点,实现了在抽象构件中定义的行为,包括那些访问及管理子构件的方法,在其业务方法中可以递归调用其子节点的业务方法。
9.装饰器模式
动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活(继承关系的替代方案)
- **主要解决:**一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。
- **何时使用:**在不想增加很多子类的情况下扩展类。
- **如何解决:**将具体功能职责划分,同时继承装饰者模式。
模式构成
- 抽象构件角色 (给出一个抽象接口,一规范接收附加责任的对象)
- 具体构件角色 (定义一个将要接受附加责任的类)
- 装饰角色 (持有一个构件对象的实例,并定义一个与抽象构件接 口一致的接口)
- 具体装饰角色 (负责给构件对象贴上附加的责任)
10.外观模式
隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口
- **意图:**为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
- **主要解决:**降低访问复杂系统的内部子系统时的复杂度,简化客户端与之的接口。
- 何时使用: 1、客户端不需要知道系统内部的复杂联系,整个系统只需提供一个"接待员"即可。 2、定义系统的入口
模式构成
- 接口
- 接口实现类(实现不同的方法)
- 外观类 xxMarker (使用实体类来代表用户对这些类的调用)
11.代理模式
在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。
模式总结
-
**意图:**为其他对象提供一种代理以控制对这个对象的访问。
-
**主要解决:**在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
-
**何时使用:**想在访问一个类时做一些控制。
-
**如何解决:**增加中间层。
-
应用实例: 1、Windows 里面的快捷方式。 2、猪八戒去找高翠兰结果是孙悟空变的,可以这样理解:把高翠兰的外貌抽象出来,高翠兰本人和孙悟空都实现了这个接口,猪八戒访问高翠兰的时候看不出来这个是孙悟空,所以说孙悟空是高翠兰代理类。 3、买火车票不一定在火车站买,也可以去代售点。 4、一张支票或银行存单是账户中资金的代理。支票在市场交易中用来代替现金,并提供对签发人账号上资金的控制。 5、spring aop。
模式构成
- 接口类
- 接口实现
- 接口代理类(直接调用接口代理类,实现对象操作)
12.责任链模式
为请求创建了一个接收者对象的链,每个接收者都包含对另一个接收者的引用,当某个接受者不能处理该请求时,会将该请求转给下一个接受者处
模式总结
-
**意图:**避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
-
**主要解决:**职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。
-
**何时使用:**在处理消息的时候以过滤很多道。
-
**如何解决:**拦截的类都实现统一接口。
-
**关键代码:**Handler 里面聚合它自己,在 HandlerRequest 里判断是否合适,如果没达到条件则向下传递,向谁传递之前 set 进去。
模式构成
- 请求者:负责请求的类型
- 处理者:负责处理请求
- 客户端:负责发出接收请求
13.命令模式
显而易见,是将命令和实际操作相隔离,解耦合,客户端只发出命令,具体的操作不需要关心,只需要完成任务。举个很简单的例子,用户点菜,然后厨师做菜,根据点菜的口味不同厨师做不同的菜
模式总结
- **意图:**将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。
- **主要解决:**在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。
- **何时使用:**在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。
- **如何解决:**通过调用者调用接受者执行命令,顺序:调用者→接受者→命令。
模式构成
Invoker(调用者):使用命令对象的入口
Command:命令
Received(命令接收者):正真的命令执行对象
14.解释器模式
是一种用得比较少的行为型模式.提供了一种解释语言的语法或表达式的方式. 通过定义一个表达式接口,解释一个特定的上下文
模式总结
- **意图:**给定一个语言,定义它的文法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子。
- **主要解决:**对于一些固定文法构建一个解释句子的解释器。
- **何时使用:**如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语言中的句子。这样就可以构建一个解释器,该解释器通过解释这些句子来解决该问题。
- **如何解决:**构件语法树,定义终结符与非终结符。
模式构成
Expression:接口(创建表达式)
SimpleExpresson:具体的实现接口(校验表达式,并输出)
15.迭代器模式
这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示
模式总结
- **意图:**提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。
- **主要解决:**不同的方式来遍历整个整合对象。
- **何时使用:**遍历一个聚合对象。
- **如何解决:**把在元素之间游走的责任交给迭代器,而不是聚合对象。
模式构成
List: 设计实现list,底层为数组,提供方法
Iterator: 迭代器,直接操作list,提供访问方法在不暴露内部的情况下
16.中介者模式
中介者模式(Mediator Pattern)是用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护
模式构成
- **意图:**用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
- **主要解决:**对象与对象之间存在大量的关联关系,这样势必会导致系统的结构变得很复杂,同时若一个对象发生改变,我们也需要跟踪与之相关联的对象,同时做出相应的处理。
- **何时使用:**多个类相互耦合,形成了网状结构。
- **如何解决:**将上述网状结构分离为星型结构。
- **关键代码:**对象 Colleague 之间的通信封装到一个类中单独处理。
模式构成
**ConcreateMeditor(中介者):**具体中介者通过协调各同事对象实现协作行为,了解并维护它的各个同事
Colleague(同事类): 规定同事内部的方法
17.备忘录模式
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象
模式总结
- **意图:**在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
- **主要解决:**所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。
- **何时使用:**很多时候我们总是需要记录一个对象的内部状态,这样做的目的就是为了允许用户取消不确定或者错误的操作,能够恢复到他原先的状态,使得他有"后悔药"可吃。
- **如何解决:**通过一个备忘录类专门存储对象状态。
- **关键代码:**客户不与备忘录类耦合,与备忘录管理类耦合
模式构成
- Originator(原型): 可设置状态
- Caretaker(保存型): 可做中间保存媒介
- Memento(保存实体): 可做为实体进行保存
18.观察者模式
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。
模式总结
- **意图:**定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
- **主要解决:**一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。
- **何时使用:**一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。
- **如何解决:**使用面向对象技术,可以将这种依赖关系弱化。
- **关键代码:**在抽象类里有一个 ArrayList 存放观察者们。
模式结构
- 观察者:负责进行
- 被观察者接口:定义操作观察者的方法,提供发布消息的方法
19.状态模式
在状态模式(State Pattern)中,类的行为是基于它的状态改变的。这种类型的设计模式属于行为型模式。
在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象
模式总结
- **意图:**允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。
- **主要解决:**对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。
- **何时使用:**代码中包含大量与对象状态有关的条件语句。
- **如何解决:**将各种具体的状态类抽象出来。
- **关键代码:**通常命令模式的接口中只有一个方法。而状态模式的接口中有一个或者多个方法。而且,状态模式的实现类的方法,一般返回值,或者是改变实例变量的值。也就是说,状态模式一般和对象的状态有关。实现类的方法有不同的功能,覆盖接口中的方法。状态模式和命令模式一样,也可以用于消除 if…else 等条件选择语句。
- 应用实例: 1、打篮球的时候运动员可以有正常状态、不正常状态和超常状态。 2、曾侯乙编钟中,‘钟是抽象接口’,'钟A’等是具体状态,'曾侯乙编钟’是具体环境(Context)。
模式结构
- State: 状态类,定义状态
- Context: 被定义状态类,可根据具体传入的状态改变
20.策略模式
在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。
模式总结
- **意图:**定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。
- **主要解决:**在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。
- **何时使用:**一个系统有许多许多类,而区分它们的只是他们直接的行为。
- **如何解决:**将这些算法封装成一个一个的类,任意地替换。
- **关键代码:**实现同一个接口。
模式结构
- Straegy:确定策略接口
- 具体策略接口: 具体的策略
- Context: 使用了某种策略的类
21.模板模式
在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。
模式总结
- **意图:**定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
- **主要解决:**一些方法通用,却在每一个子类都重新写了这一方法。
- **何时使用:**有一些通用的方法。
- **如何解决:**将这些通用算法抽象出来。
- **关键代码:**在抽象类实现,其他步骤在子类实现。
- 应用实例: 1、在造房子的时候,地基、走线、水管都一样,只有在建筑的后期才有加壁橱加栅栏等差异。 2、西游记里面菩萨定好的 81 难,这就是一个顶层的逻辑骨架。 3、spring 中对 Hibernate 的支持,将一些已经定好的方法封装起来,比如开启事务、获取 Session、关闭 Session 等,程序员不重复写那些已经规范好的代码,直接丢一个实体就可以保存。
模式结构
- **模板类:**定义模板方法
- **模板实现类:**模板实现的具体方法
22.访问者模式
表示一个作用于其对象结构中的各元素的操作,它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作
模式总结
- **意图:**主要将数据结构与数据操作分离。
- **主要解决:**稳定的数据结构和易变的操作耦合问题。
- **何时使用:**需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,使用访问者模式将这些封装到类中。
- **如何解决:**在被访问的类里面加一个对外提供接待访问者的接口。
- **关键代码:**在数据基础类里面有一个方法接受访问者,将自身引用传入访问者。
- **应用实例:**您在朋友家做客,您是访问者,朋友接受您的访问,您通过朋友的描述,然后对朋友的描述做出一个判断,这就是访问者模式
模式结构
- 基础类:提供基础方法
- 访问者:在不改变基础类的同时,传入访问者
23.享元模式
享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式
模式总结
- **意图:**运用共享技术有效地支持大量细粒度的对象。
- **主要解决:**在有大量对象时,有可能会造成内存溢出,我们把其*同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。
- 何时使用: 1、系统中有大量对象。 2、这些对象消耗大量内存。 3、这些对象的状态大部分可以外部化。 4、这些对象可以按照内蕴状态分为很多组,当把外蕴对象从对象中剔除出来时,每一组对象都可以用一个对象来代替。 5、系统不依赖于这些对象身份,这些对象是不可分辨的。
- **如何解决:**用唯一标识码判断,如果在内存中有,则返回这个唯一标识码所标识的对象。
- **关键代码:**用 HashMap 存储这些对象。
- 应用实例: 1、JAVA 中的 String,如果有则返回,如果没有则创建一个字符串保存在字符串缓存池里面。 2、数据库的数据池。
上一篇: Java编程思想笔记——容器深入研究3
下一篇: 朴素匹配