模板方法
在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。
定义一个操作中的==算法的骨架==,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定功能。
炒菜案例:
分析:
1.取材
2.处理食材
3.起锅烧油
4.放入食材
5.翻炒
6.放入各种调料
7.翻炒均匀
8.出锅
public abstract class ChaoCai {
//不能被子类重写
public final void chaocai(){
quShiCai();
handle();
qiGuoShaoYou();
putShiCai();
fanChao();
putTiaoLiao();
junYun();
outGuo();
}
//1.取食材
void quShiCai(){};
//2.处理食材
void handle(){};
//3.起锅烧油
void qiGuoShaoYou(){};
//4.放入食材
void putShiCai(){};
//5.翻炒
void fanChao(){};
//6.放入各种调料
void putTiaoLiao(){};
//7.翻炒均匀
void junYun(){};
//8.出锅
void outGuo(){};
}
番茄炒菜
public class FanQieChaoDan extends ChaoCai{
@Override
void quShiCai() {
System.out.println("取鸡蛋和番茄");
}
@Override
void handle() {
System.out.println("处理鸡蛋和番茄");
}
@Override
void qiGuoShaoYou() {
System.out.println("起锅烧油");
}
@Override
void putShiCai() {
System.out.println("翻入鸡蛋和番茄");
}
@Override
void fanChao() {
System.out.println("翻炒");
}
@Override
void putTiaoLiao() {
System.out.println("翻入调料");
}
@Override
void junYun() {
System.out.println("翻炒均匀");
}
@Override
void outGuo() {
System.out.println("出锅!");
}
}
测试:
public class ChaoCaiTest {
public static void main(String[] args) {
FanQieChaoDan fanQieChaoDan = new FanQieChaoDan();
fanQieChaoDan.chaocai();
}
}
优点:
1、封装不变部分,扩展可变部分。
2、提取公共代码,便于维护。
3、行为由父类控制,子类实现。
缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
使用场景:
1、有多个子类共有的方法,且逻辑相同。
2、重要的、复杂的方法,可以考虑作为模板方法。
注意事项:为防止恶意操作,一般模板方法都加上 final 关键词。
观察者模式
观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。
观察者模式的主要角色如下。
抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
实现
观察者模式首先有一个被观察类,这个类中有一个 ArrayList 存放观察者们。除此以外还应有类状态和设置和获取状态的方法,状态改变时通知所有观察者,观察者类可以有个抽象类,所有的观察者类继承这个抽象类,观察者类有它要观察的对象。
例子
需求:做一个案例,公众号推送消息,关注这个公众号的客户可以接收到消息。
1. 抽象主题---抽象公共号
1. 关注
2. 取消关注
3. 设置推送的消息
4. 群发
2. 具体主题--具体公众号类AAA
3. 抽象观察者---抽象用户
1. 接受消息分析:
观察者模式分为四个角色:
1.抽象被观察者角色
抽象出一个公众号接口/抽象类
公共的方法:
关注方法
取关方法
设置推送消息方法
群发方法2.被观察者角色
有一个具体的公众号,实现/继承 抽象被观察者3.抽象观察者角色
抽象出一个客户 接口/抽象类
公共方法:
接收公众号推送的消息
4.观察者角色
具体用户 实现/继承 抽象观察者
抽象观察者角色:
package demo02;
public interface UserInterface {
/**
* 接受公众号发生的消息
* @param msg
*/
public void getMsg(String msg);
}
观察者角色:
package demo02;
public class User implements UserInterface {
private String name;
public User(String name) {
this.name = name;
}
public void getMsg(String msg) {
System.out.println(name+"接受到公众号发送的消息:"+msg);
}
}
抽象公众号:
package demo02;
public interface PublicHaoInterface {
public void add(UserInterface userInterface);
public void remove(UserInterface userInterface);
public void setMsg(String msg);
public void qunfa();
}
具体公共号:
package demo02;
import java.util.ArrayList;
import java.util.List;
public class AAAPublicHao implements PublicHaoInterce {
List<UserInterface> list=new ArrayList<UserInterface>();
//设置消息
private String msg;
public void add(UserInterface userInterface) {
list.add(userInterface);
}
public void remove(UserInterface userInterface) {
list.remove(userInterface);
}
public void setMsg(String msg) {
this.msg=msg;
}
public void qunfa() {
for(UserInterface userInterface:list){
userInterface.getMsg(msg);
}
}
}
优缺点
观察者模式是一种对象行为型模式,其主要优点如下。
降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。 目标与观察者之间建立了一套触发机制。
它的主要缺点如下。
目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。
策略模式
什么是策略模式:
将类中经常改变或者可能改变的部分提取为作为一个抽象策略接口类,然后在类中包含这个对象的实例,这样类实例在运行时就可以随意调用实现了这个接口的类的行为。
比如定义一系列的算法,把每一个算法封装起来,并且使它们可相互替换,使得算法可独立于使用它的客户而变化,这就是策略模式。
案例
促销活动。
public class CuXiaoContext {
private CuXiao cuXiao;
public CuXiaoContext(CuXiao cuXiao) {
this.cuXiao = cuXiao;
}
//定义一个使用算法的方法
public void use(){
cuXiao.cuxiao();
}
}
public interface CuXiao {
void cuxiao();
}
public class SuanFa618 implements CuXiao {
@Override
public void cuxiao() {
System.out.println("使用6.18的促销算法");
}
}
public class SuanFa1111 implements CuXiao{
@Override
public void cuxiao() {
System.out.println("使用11.11的促销算法");
}
}
public class SuanFa1212 implements CuXiao{
@Override
public void cuxiao() {
System.out.println("使用12.12的促销算法");
}
}
public class CuXiaoTest {
public static void main(String[] args) {
//SuanFa618 suanFa618 = new SuanFa618();
SuanFa1111 suanFa1111 = new SuanFa1111();
CuXiaoContext context = new CuXiaoContext(suanFa1111);
context.use();
}
}
策略模式优缺点:
优点:
1、算法可以自由切换(策略类自由切换)。
2、避免使用多重条件判断。
3、扩展性良好(符合开闭原则)。
缺点:
1、策略类会增多。
2、所有策略类都需要对外暴露。
3、客户端必须知道所有的策略类,才能确定要调用的策略类。
策略模式使用场景:
-
如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
-
一个系统需要动态地在几种算法中选择一种。
-
如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
命令模式
命令模式基本介绍
1) 命令模式(Command Pattern):在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计
2) 命名模式使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活,实现解耦。
3) 在命名模式中,会将一个请求封装为一个对象,以便使用不同参数来表示不同的请求(即命名),同时命令模式也支持可撤销的操作。
4) 通俗易懂的理解:将军发布命令,士兵去执行。其中有几个角色:将军(命令发布者)、士兵(命令的具体执行者)、命令(连接将军和士兵)。Invoker 是调用者(将军),Receiver 是被调用者(士兵),MyCommand 是命令,实现了 Command 接口,持有接收对象
命令模式的原理类图
对原理类图的说明-即(命名模式的角色及职责)
1) Invoker 是调用者角色
2) Command: 是命令角色,需要执行的所有命令都在这里,可以是接口或抽象类
3) Receiver: 接受者角色,知道如何实施和执行一个请求相关的操作
4) ConcreteCommand: 将一个接受者对象与一个动作绑定,调用接受者相应的操作,实现 execute
命令模式的注意事项和细节
1) 将发起请求的对象与执行请求的对象解耦。发起请求的对象是调用者,调用者只要调用命令对象的 execute()方法就可以让接收者工作,而不必知道具体的接收者对象是谁、是如何实现的,命令对象会负责让接收者执行请求的动作,也就是说:”请求发起者”和“请求执行者”之间的解耦是通过命令对象实现的,命令对象起到了纽带桥梁的作用。
2) 容易设计一个命令队列。只要把命令对象放到列队,就可以多线程的执行命令
3) 容易实现对请求的撤销和重做
4) 命令模式不足:可能导致某些系统有过多的具体命令类,增加了系统的复杂度,这点在在使用的时候要注意
5) 空命令也是一种设计模式,它为我们省去了判空的操作。在上面的实例中,如果没有用空命令,我们每按下一个按键都要判空,这给我们编码带来一定的麻烦。
6) 命令模式经典的应用场景:界面的一个按钮都是一条命令、模拟 CMD(DOS 命令)订单的撤销/恢复、触发-反馈机制
访问者模式
访问者模式基本介绍
1) 访问者模式(Visitor Pattern),封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
2) 主要将数据结构与数据操作分离,解决 数据结构和操作耦合性问题
3) 访问者模式的基本工作原理是:在被访问的类里面加一个对外提供接待访问者的接口
4) 访问者模式主要应用场景是:需要对一个对象结构中的对象进行很多不同操作(这些操作彼此没有关联),同时需要避免让这些操作"污染"这些对象的类,可以选用访问者模式解决
访问者模式的注意事项和细节
优点
1) 访问者模式符合单一职责原则、让程序具有优秀的扩展性、灵活性非常高
2) 访问者模式可以对功能进行统一,可以做报表、UI、拦截器与过滤器,适用于数据结构相对稳定的系统
缺点
1) 具体元素对访问者公布细节,也就是说访问者关注了其他类的内部细节,这是迪米特法则所不建议的, 这样造成了具体元素变更比较困难
2) 违背了依赖倒转原则。访问者依赖的是具体元素,而不是抽象元素
3) 因此,如果一个系统有比较稳定的数据结构,又有经常变化的功能需求,那么访问者模式就是比较合适的.
迭代器模式
迭代器模式基本介绍
1) 迭代器模式(Iterator Pattern)是常用的设计模式,属于行为型模式
2) 如果我们的集合元素是用不同的方式实现的,有数组,还有 java 的集合类,或者还有其他方式,当客户端要遍历这些集合元素的时候就要使用多种遍历方式,而且还会暴露元素的内部结构,可以考虑使用迭代器模式解决。
3) 迭代器模式,提供一种遍历集合元素的统一接口,用一致的方法遍历集合元素,不需要知道集合对象的底层表示,即:不暴露其内部的结构。
迭代器模式的注意事项和细节
优点
1) 提供一个统一的方法遍历对象,客户不用再考虑聚合的类型,使用一种方法就可以遍历对象了。
2) 隐藏了聚合的内部结构,客户端要遍历聚合的时候只能取到迭代器,而不会知道聚合的具体组成。
3) 提供了一种设计思想,就是一个类应该只有一个引起变化的原因(叫做单一责任原则)。在聚合类中,我们把迭代器分开,就是要把管理对象集合和遍历对象集合的责任分开,这样一来集合改变的话,只影响到聚合对象。而如果遍历方式改变的话,只影响到了迭代器。
4) 当要展示一组相似对象,或者遍历一组相同对象时使用, 适合使用迭代器模式缺点
每个聚合对象都要一个迭代器,会生成多个迭代器不好管理类
中介者模式
中介者模式基本介绍
基本介绍
1) 中介者模式(Mediator Pattern),用一个中介对象来封装一系列的对象交互。中介者使各个对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互
2) 中介者模式属于行为型模式,使代码易于维护
3) 比如 MVC 模式,C(Controller 控制器)是 M(Model 模型)和 V(View 视图)的中介者,在前后端交互时起到了中间人的作用
中介者模式的注意事项和细节
1) 多个类相互耦合,会形成网状结构, 使用中介者模式将网状结构分离为星型结构,进行解耦
2) 减少类间依赖,降低了耦合,符合迪米特原则
3) 中介者承担了较多的责任,一旦中介者出现了问题,整个系统就会受到影响
4) 如果设计不当,中介者对象本身变得过于复杂,这点在实际使用时,要特别注意
备忘录模式
备忘录模式基本介绍
基本介绍
1) 备忘录模式(Memento Pattern)在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态2) 可以这里理解备忘录模式:现实生活中的备忘录是用来记录某些要去做的事情,或者是记录已经达成的共同意
见的事情,以防忘记了。而在软件层面,备忘录模式有着相同的含义,备忘录对象主要用来记录一个对象的某
种状态,或者某些数据,当要做回退时,可以从备忘录对象里获取原来的数据进行恢复操作
3) 备忘录模式属于行为型模式
备忘录模式的注意事项和细节
1) 给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态
2) 实现了信息的封装,使得用户不需要关心状态的保存细节
3) 如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存, 这个需要注意
4) 适用的应用场景:1、后悔药。 2、打游戏时的存档。 3、Windows 里的 ctri + z。 4、IE 中的后退。 4、数据库的事务管理5) 为了节约内存,备忘录模式可以和原型模式配合使用
解释器模式
解释器模式基本介绍
1) 在编译原理中,一个算术表达式通过词法分析器形成词法单元,而后这些词法单元再通过语法分析器构建语法
分析树,最终形成一颗抽象的语法分析树。这里的词法分析器和语法分析器都可以看做是解释器
2) 解释器模式(Interpreter Pattern):是指给定一个语言(表达式),定义它的文法的一种表示,并定义一个解释器,使用该解释器来解释语言中的句子(表达式)
3) 应用场景
应用可以将一个需要解释执行的语言中的句子表示为一个抽象语法树
一些重复出现的问题可以用一种简单的语言来表达一个简单语法需要解释的场景
4) 这样的例子还有,比如编译器、运算表达式计算、正则表达式、机器人等
解释器模式的注意事项和细节
1) 当有一个语言需要解释执行,可将该语言中的句子表示为一个抽象语法树,就可以考虑使用解释器模式,让程序具有良好的扩展性
2) 应用场景:编译器、运算表达式计算、正则表达式、机器人等
3) 使用解释器可能带来的问题:解释器模式会引起类膨胀、解释器模式采用递归调用方法,将会导致调试非常复杂、效率可能降低.
状态模式
状态模式基本介绍
1) 状态模式(State Pattern):它主要用来解决对象在多种状态转换时,需要对外输出不同的行为的问题。状态和行为是一一对应的,状态之间可以相互转换
2) 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类
状态模式的注意事项和细节
1) 代码有很强的可读性。状态模式将每个状态的行为封装到对应的一个类中
2) 方便维护。将容易产生问题的 if-else 语句删除了,如果把每个状态的行为都放到一个类中,每次调用方法时都要判断当前是什么状态,不但会产出很多 if-else 语句,而且容易出错
3) 符合“开闭原则”。容易增删状态
4) 会产生很多类。每个状态都要一个对应的类,当状态过多时会产生很多类,加大维护难度
5) 应用场景:当一个事件或者对象有很多种状态,状态之间会相互转换,对不同的状态要求有不同的行为的时候,可以考虑使用状态模式
职责链模式
职责链模式基本介绍
1) 职责链模式(Chain of Responsibility Pattern), 又叫 责任链模式,为请求创建了一个接收者对象的链(简单示意图)。这种模式对请求的发送者和接收者进行解耦。
2) 职责链模式通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
3) 这种类型的设计模式属于行为型模式
职责链模式的注意事项和细节
1) 将请求和处理分开,实现解耦,提高系统的灵活性
2) 简化了对象,使对象不需要知道链的结构
3) 性能会受到影响,特别是在链比较长的时候,因此需控制链中最大节点数量,一般通过在 Handler 中设置一个最大节点数量,在 setNext()方法中判断是否已经超过阀值,超过则不允许该链建立,避免出现超长链无意识地破坏系统性能4) 调试不方便。采用了类似递归的方式,调试时逻辑可能比较复杂
5) 最佳应用场景:有多个对象可以处理同一个请求时,比如:多级请求、请假/加薪等审批流程、Java Web 中 Tomcat对 Encoding 的处理、拦截器