模板模式
豆浆制作问题
- 制作豆浆的流程选材–>添加配料—>浸泡—>放到豆浆机打碎通过添加不同的配料,可以制作出不同口味的豆浆
- 选材、浸泡和放到豆浆机打碎这几个步骤对于制作每种口味的豆浆都是一样的
- 请使用模板方法模式完成(说明:因为模板方法模式,比较简单,很容易就想到这个方案,因此就直接使用,不再使用传统的方案来引出模板方法模式)
基本介绍
模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern),在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
简单说,模板方法模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤
这种类型的设计模式属于行为型模式。
AbstractClass
: 类中实现了模板方法,定义了算法的骨架,具体子类需要去实现其他的抽象方法ConcreateClass
: 实现抽象方法,完成特定的步骤
应用实例
// 抽象类
public abstract class SoyaMilk {
// 模板方法 makeTemplate 模板方法可以做成final 不让子类取覆盖
final void makeTemplate() {
this.select();
this.add();
this.soak();
this.beat();
}
// 选材料
void select() {
System.out.println("选材");
}
// 添加辅料 不同的豆浆 辅料不同 由子类去实现
abstract void add();
// 浸泡
void soak() {
System.out.println("浸泡");
}
// 制作
void beat() {
System.out.println("制作");
}
}
// 红豆豆浆
class ReadBeanSoyaMilk extends SoyaMilk {
@Override
void add() {
System.out.println("加入红豆");
}
}
// 花生豆浆
class PeanutSoyaMilk extends SoyaMilk {
@Override
void add() {
System.out.println("加入花生");
}
}
// 客户端
class Client {
public static void main(String[] args) {
SoyaMilk soyaMilk = new ReadBeanSoyaMilk();
soyaMilk.makeTemplate();
}
}
模板方法模式的钩子方法
在模板方法模式的父类中,我们可以定义一个方法,它默认不做任何事,子类可以视情况要不要覆盖它,该方法称为“钩子”。
还是用上面做豆浆的例子来讲解,比如,我们还希望制作纯豆浆,不添加任何的配料,请使用钩子方法对前面的模板方法进行改造
// 抽象类
public abstract class SoyaMilk {
// 模板方法 makeTemplate 模板方法可以做成final 不让子类去覆盖
final void makeTemplate() {
this.select();
// 判断是否需要加入辅料
if (this.isAdd()) {
this.add();
}
this.soak();
this.beat();
}
// 选材料
void select() {
System.out.println("选材");
}
// 添加辅料 不同的豆浆 辅料不同 由子类去实现
abstract void add();
// 浸泡
void soak() {
System.out.println("浸泡");
}
// 制作
void beat() {
System.out.println("制作");
}
// 钩子方法 是否添加辅料
boolean isAdd() {
return true;
}
}
// 制作纯豆浆 不添加任何辅料
class PeanutSoyaMilk1 extends SoyaMilk {
@Override
void add() {
// 空实现
}
// 重写钩子方法
@Override
boolean isAdd() {
return false;
}
}
模板方法模式的注意事项和细节
- 基本思想是: 算法只存在于一个地方,也就是在父类中,容易修改。需要修改算法时,只要修改父类的模板方法或着已经实现的某些步骤,子类就会继承这些修改实现了最大化代码复用。父类的模板方法和已实现的某些步骤会被子类继承而直接使用。
- 既统一了算法,也提供了很大的灵活性。父类的模板方法确保了算法的结构保持不变,同时由子类提供部分步骤的实现。
- 该模式的不足之处:每一个不同的实现都需要一个子类实现,导致类的个数增加,使得系统更加庞大
- 一般模板方法都加上final关键字,防止子类重写模板方法.
- 模板方法模式使用场景:当要完成在某个过程,该过程要执行一系列步骤,这一系列的步骤基本相同,但其个别步骤在实现时可能不同 ,通常考虑用模板方法模式来处理
命令模式
智能生活项目需求
我们买了一套智能家电。有照明灯、风扇、冰箱、洗衣机,我们只要在手机上安装app就可以控制对这些家电工作。
这些智能家电来自不同的厂家。我们不想针对每一种家电都安装一个App,分别控制,我们希望只要一个app就可以控制全部智能家电。
要实现一个appi控制所有智能家电的需要。则每个智能家电厂家都要提供一个统一的接口给app调用,这时就可以考虑使用命令模式。
命令模式可将“动作的请求者”从“动作的执行者”对象中解耦出来。
在我们的例子中,动作的请求者是手机app,动作的执行者是每个厂商的一个家电产品
基本介绍
- 命令模式(Command Pattem):在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个
- 我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计
- 命名模式使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活,实现解耦。
- 在命名模式中,会将一个请求封装为一个对象,以便使用不同参故来表示不同的请求(即命名),同时命令模式也支持可撤销的操作通俗易懂的理解:将军发布命令·士兵去执行。其中有几个角色:将军(命令发布者)、士兵(命令的具体执行者)、命令(连接将军和士兵)。
- Invoker是调用者(将军).Receiver是被调用者(士兵)·MyCommand是命令,实现了Command接口,持有接收对象
命令模式包含以下主要角色。
- 抽象命令类(Command)角色:声明执行命令的接口,拥有执行命令的抽象方法 execute()。
- 具体命令类(Concrete Command)角色:是抽象命令类的具体实现类,它拥有接收者对象,并通过调用接收者的功能来完成命令要执行的操作。
- 实现者/接收者(Receiver)角色:执行命令功能的相关操作,是具体命令对象业务的真正实现者。
- 调用者/请求者(Invoker)角色:是请求的发送者,它通常拥有很多的命令对象,并通过访问命令对象来执行相关请求,它不直接访问接收者。
应用实例
// 命令接口
public interface Command {
// 执行
void execute();
// 撤销
void undo();
}
// 命令具体的执行者
public class LightReceiver {
public void on() {
System.out.println("电灯打开");
}
public void off() {
System.out.println("电灯关闭");
}
}
// 具体命令类 电灯打开
public class LightOnCommand implements Command {
private LightReceiver lightReceiver;
public LightOnCommand(LightReceiver lightReceiver) {
this.lightReceiver = lightReceiver;
}
@Override
public void execute() {
lightReceiver.on();
}
@Override
public void undo() {
lightReceiver.off();
}
}
// 具体命令类 电灯关闭
public class LightOffCommand implements Command {
private LightReceiver lightReceiver;
public LightOffCommand(LightReceiver lightReceiver) {
this.lightReceiver = lightReceiver;
}
@Override
public void execute() {
lightReceiver.off();
}
@Override
public void undo() {
lightReceiver.on();
}
}
// 准备一个空命令 可以简化操作 简化对空的判断 也可以用于初始化每个按钮
public class NoCommand implements Command {
@Override
public void execute() {
// 空实现
}
@Override
public void undo() {
// 空实现
}
}
// 遥控器
public class RemoteController {
// 打开命令集合
Command[] onCommand;
// 关闭命令集合
Command[] offCommand;
// 撤销命令 记录上一步的操作
Command undoCommand;
// 初始化
{
onCommand = new Command[5];
offCommand = new Command[5];
for (int i = 0; i < 5; i++) {
NoCommand command = new NoCommand();
onCommand[i] = command;
offCommand[i] = command;
}
}
// 给我们的按钮设置成需要的命令
public void setCommand(int sort, Command on, Command off) {
onCommand[sort] = on;
offCommand[sort] = off;
}
// 按下打开按钮
public void onButton(int sort) {
// 打开按钮
onCommand[sort].execute();
// 记录上一步操作
undoCommand = onCommand[sort];
}
// 关闭按钮
public void offButton(int sort) {
offCommand[sort].execute();
undoCommand = offCommand[sort];
}
// 撤销
public void undoButton() {
undoCommand.undo();
}
}
class Client {
public static void main(String[] args) {
// 创建电灯接收者
LightReceiver receiver = new LightReceiver();
// 创建电脑打开命令
LightOnCommand onCommand = new LightOnCommand(receiver);
// 创建电灯关闭命令
LightOffCommand offCommand = new LightOffCommand(receiver);
// 创建遥控器
RemoteController controller = new RemoteController();
// 设置相关命令
controller.setCommand(0, onCommand, offCommand);
// 调用命令
controller.onButton(0);
controller.offButton(0);
controller.undoButton();
}
}
命令模式的注意事项和细节
- 将发起请求的对象与执行请求的对象解耦。发起请求的对象是调用者,调用者只要调用命令对象的
execute()
方法就可以让接收者工作,而不必知道具体的接收者对象是谁、是如何实现的,命令对象会负责让接收者执行请求的动作,也就是说:”请求发起者”和“请求执行者”之间的解耦是通过命令对象实现的,命令对象起到了纽带桥梁的作用。 - 容易设计一个命令队列。只要把命令对象放到列队,就可以多线程的执行命令容易实现对请求的撤销和重做
- 命令模式不足: 可能导致某些系统有过多的具体命令类,增加了系统的复杂度,这点在在使用的时候要注意
- 空命令也是一种设计模式,它为我们省去了判空的操作。在上面的实例中,如果没有用空命令,我们每按下一个按键都要判空,这给我们编码带来一定的麻烦。
- 命令模式经典的应用场景:界面的一个按钮都是一条命令、模拟CMD (DOS命令)订单的撤销/恢复、触发-反馈机制
访问者模式
测评系统需求
完成测评系统需求
1)将人分为男人和女人,对歌手进行测评,当看完某个歌手表演后,得到他们对该
歌手不同的评价(评价有不同的种类,比如成功、失败等)
基本介绍
- 访问者模式(Visitor Pattern),封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
- 主要将数据结构与数据操作分离,解决数据结构和操作耦合性问题
- 访问者模式的基本工作原理是:在被访问的类里面加一个对外提供接待访问者的接口
- 访问者模式主要应用场景是: 需要对一个对象结构中的对象进行很多不同操作(这些操作彼此没有关联),同时需要避免让这些操作"污染"这些对象的类,可以选用访问者模式解决
访问者模式包含以下主要角色:
- 抽象访问者(Visitor)角色:定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作 visit() ,该操作中的参数类型标识了被访问的具体元素。
- 具体访问者(ConcreteVisitor)角色:实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么。
- 抽象元素(Element)角色:声明一个包含接受操作 accept() 的接口,被接受的访问者对象作为 accept() 方法的参数。
- 具体元素(ConcreteElement)角色:实现抽象元素角色提供的 accept() 操作,其方法体通常都是 visitor.visit(this) ,另外具体元素中可能还包含本身业务逻辑的相关操作。
- 对象结构(Object Structure)角色:是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由 List、Set、Map 等聚合类实现。
应用实例
public interface Action {
// 获取男人的评价
void getManResult(Man man);
// 获取女人的评价
void getWoManResult(WoMan man);
}
public class Success implements Action {
@Override
public void getManResult(Man man) {
System.out.println("男人给的评价是成功");
}
@Override
public void getWoManResult(WoMan man) {
System.out.println("女人给的评价是成功");
}
}
public class Fail implements Action {
@Override
public void getManResult(Man man) {
System.out.println("男人给的评价是失败");
}
@Override
public void getWoManResult(WoMan man) {
System.out.println("女人给的评价是失败");
}
}
public interface Person {
void accept(Action action);
}
public class Man implements Person {
@Override
public void accept(Action action) {
action.getManResult(this);
}
}
public class WoMan implements Person {
@Override
public void accept(Action action) {
action.getWoManResult(this);
}
}
public class ObjectStructure {
// Element 集合
private List<Person> list = new LinkedList<>();
public void add(Person person) {
list.add(person);
}
public void remove(Person person) {
list.remove(person);
}
// 显示测评结果
public void display(Action action) {
for (Person person : list) {
person.accept(action);
}
}
}
public class Client {
public static void main(String[] args) {
// 创建对象结构
ObjectStructure objectStructure = new ObjectStructure();
// 添加打分者
objectStructure.add(new Man());
objectStructure.add(new WoMan());
// 打分
Success success = new Success();
objectStructure.display(success);
}
}
访问者模式的注意事项和细节
优点
访问者模式符合单一职责原则、让程序具有忧秀的扩展性、灵活性非常高
访问者模式可以对功能进行统一,可以做报表、UI、拦截器与过滤器,适用于数据结构相对稳定的系统
缺点
具体元素对访问者公布细节,也就是说访问者关注了其他类的内部细节,这是迪米特法则所不建议的,这样造成了具体元素变更比较困难
违背了依赖倒转原则。访问者依赖的是具体元素,而不是抽象元素
因此,如果一个系统有比较稳定的数据结构,又有经常变化的功能需求,那么访问者模式就是比较合适的
迭代器模式
学校院系展示需求
看一个学校院系展示需求
编写程序展示一个学校院系结构:需求是这样,要在一个页面中展示出学校的院系组成,一个学校有多个学院,一个学院有多个系。如图:
----清华大学---- |
---|
----计算机学院---- |
计算机科学与技术 |
软件工程 |
网络工程 |
----信息工程学院---- |
通信工程 |
信息工程 |
基本介绍
- 迭代器摸式(lterator Pattern)是常用的设计模式,属于行为型模式
- 如果我们的集合元素是用不同的方式实现的,有数组,还有Java的集合为或者还有其他方式,当客户端要遍历这些集合元素的时候就要使用多种遍历方式,而且还会暴露元素的内部结构,可以考虑使用迭代器模式解决。
- 迭代器模式,提供一种遍历集合元素的统一接口,用 一致的方法 遍历集合元素,不需要知道集合对象的底层表示,即:不暴露其内部的结构。
迭代器模式主要包含以下角色。
- 抽象聚合(Aggregate)角色:定义存储、添加、删除聚合对象以及创建迭代器对象的接口。
- 具体聚合(ConcreteAggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例。
- 抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含
hasNext()
、first()
、next()
等方法。JDK提供的接口 - 具体迭代器(Concretelterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。
应用实例
// 院系
public class Department {
private String id;
private String name;
public Department(String id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Department{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}
// 具体迭代器(Concretelterator)角色 如果院系是用List来存放的就使用这个迭代器
public class InfoCollegeIterator implements Iterator {
private List<Department> departments;
private int index = 0;
public InfoCollegeIterator(List<Department> departments) {
this.departments = departments;
}
// 判断集合
@Override
public boolean hasNext() {
if (index >= departments.size() -1 ) {
return false;
}
return true;
}
// 获取集合中的元素
@Override
public Object next() {
Department department = departments.get(index);
index++; // 指针指向下一个元素
return department;
}
}
// 具体迭代器(Concretelterator)角色 如果院系是用数组来存放的就使用这个迭代器
public class ComputerCollegeIterator implements Iterator {
// 遍历的数组
private Department[] departments;
// 遍历的位置
private int position = 0;
public ComputerCollegeIterator(Department[] departments) {
this.departments = departments;
}
// 遍历数组
@Override
public boolean hasNext() {
if (position >= departments.length || departments[position] == null) {
return false;
}
return true;
}
// 获取数组元素
@Override
public Object next() {
Department department = departments[position];
position ++; // 指针指向下一个元素
return department;
}
}
public interface College {
// 获取学院名称
String getName();
// 增加系的方法
void addDepartment(String id, String name);
// 返回迭代器
public Iterator getIterator();
}
class ComputerCollege implements College {
private Department[] departments;
private int numOfDepartment = 0; // 保存当前数组的对象个数
{
departments = new Department[5];
departments[numOfDepartment] = new Department("0", "计算机科学与技术");
numOfDepartment++;
departments[numOfDepartment] = new Department("1", "软件工程");
numOfDepartment++;
}
@Override
public String getName() {
return "计算机学院";
}
// 加入元素
@Override
public void addDepartment(String id, String name) {
Department department = new Department(id, name);
departments[numOfDepartment] = department;
numOfDepartment++;
}
// 获取迭代器
@Override
public Iterator getIterator() {
return new ComputerCollegeIterator(departments);
}
}
class InfoCollege implements College {
private List<Department> departments;
{
departments = new ArrayList<>();
departments.add(new Department("0", "信息安全"));
departments.add(new Department("1", "网络安全"));
}
@Override
public String getName() {
return "信息工程学院";
}
@Override
public void addDepartment(String id, String name) {
departments.add(new Department(id, name));
}
@Override
public Iterator getIterator() {
return new InfoCollegeIterator(departments);
}
}
// 输出
public class OutPutCollegeImpl {
public void outputDepartments(Iterator iterator) {
while (iterator.hasNext()) {
Department next = (Department) iterator.next();
System.out.println(next.toString());
}
}
}
// 客户端
class Client {
public static void main(String[] args) {
// 获取数据
ComputerCollege college = new ComputerCollege();
Iterator iterator = college.getIterator();
OutPutCollegeImpl outPutCollege = new OutPutCollegeImpl();
outPutCollege.outputDepartments(iterator);
}
}
迭代器模式在JDK底层的应用
在ArrayList
中使用到了迭代器模式
/**
* Returns an iterator over the elements in this list in proper sequence.
*
* <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
*
* @return an iterator over the elements in this list in proper sequence
*/
public Iterator<E> iterator() {
return new Itr();
}
/**
* An optimized version of AbstractList.Itr
*/
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
迭代器模式的注意事项和细节
优点
提供一个统一的方法遍历对象,客户不用再考虑聚合的类型,使用一种方法就可以遍历对象了。
隐藏了聚合的内部结构,客户端要遍历聚合的时候只能取到迭代器,而不会知道聚合的具体组成。
提供了一种设计思想,就是一个类应该只有一个引起变化的原因(叫做单一责任原则)。在聚合类中,我们把迭代器分开,就是要把管理对象集合和遍历对象集合的责任分开,这样一来集合改变的话,只影响到聚合对象。而如果遍历方式改变的话,只影响到了迭代器。
当要展示一组相似对象,或者遍历一组相同对象时使用,适合使用迭代器模式
缺点
每个聚合对象都要一个迭代器,会生成多个迭代器不好管理类
观察者模式
天气预报项目需求
气象站可以将每天测量到的温度,湿度,气压等等以公告的形式发布出去(比如发布到自己的网站或第三方)。
需要设计开放型API,便于其他第三方也能接入气象站获取数据。
提供温度、气压和湿度的接口
测量数据更新时,要能实时的通知给第三方
基本介绍
观察者(Observer)模式的定义:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。
观察者模式的主要角色如下。
- 抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
- 具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
- 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
- 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
基本介绍
// 抽象观察者(Observer)角色
public interface Observer {
void update(float temper, float humid);
// 具体观察者(Concrete Observer)角色
class tencent implements Observer {
@Override
public void update(float temper, float humid) {
System.out.println("tencent获得参数:" + temper + "," + humid);
}
}
// 具体观察者(Concrete Observer)角色
class baidu implements Observer {
@Override
public void update(float temper, float humid) {
System.out.println("baidu:" + temper + "," + humid);
}
}
}
// 抽象主题(Subject)角色
public interface Subject {
// 加入观察者
void add(Observer observer);
// 移除观察者
void remove(Observer observer);
// 通知所有观察者
void notifyObserver();
// 具体主题(Concrete Subject)角色
class WeatherData implements Subject {
private List<Observer> observers = new ArrayList<>();
@Override
public void add(Observer observer) {
observers.add(observer);
}
@Override
public void remove(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObserver() {
for (Observer observer : observers) {
observer.update(1.1F, 1.2F);
}
}
}
}
// 客户端
class Client {
public static void main(String[] args) {
// 创建观察者
Observer tencent = new Observer.tencent();
Observer baidu = new Observer.baidu();
// 创建主题
Subject weatherData = new Subject.WeatherData();
weatherData.add(tencent);
weatherData.add(baidu);
// 通知所有观察者
weatherData.notifyObserver();
}
}
观察者模式在JDK底层的应用
/**
* A class can implement the <code>Observer</code> interface when it
* wants to be informed of changes in observable objects.
*
* @author Chris Warth
* @see java.util.Observable
* @since JDK1.0
*/
public interface Observer {
/**
* This method is called whenever the observed object is changed. An
* application calls an <tt>Observable</tt> object's
* <code>notifyObservers</code> method to have all the object's
* observers notified of the change.
*
* @param o the observable object.
* @param arg an argument passed to the <code>notifyObservers</code>
* method.
*/
void update(Observable o, Object arg);
}
// 主题(Subject)角色
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;
/** Construct an Observable with zero Observers. */
public Observable() {
obs = new Vector<>();
}
/**
* Adds an observer to the set of observers for this object, provided
* that it is not the same as some observer already in the set.
* The order in which notifications will be delivered to multiple
* observers is not specified. See the class comment.
*
* @param o an observer to be added.
* @throws NullPointerException if the parameter o is null.
*/
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
/**
* Deletes an observer from the set of observers of this object.
* Passing <CODE>null</CODE> to this method will have no effect.
* @param o the observer to be deleted.
*/
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
/**
* If this object has changed, as indicated by the
* <code>hasChanged</code> method, then notify all of its observers
* and then call the <code>clearChanged</code> method to
* indicate that this object has no longer changed.
* <p>
* Each observer has its <code>update</code> method called with two
* arguments: this observable object and <code>null</code>. In other
* words, this method is equivalent to:
* <blockquote><tt>
* notifyObservers(null)</tt></blockquote>
*
* @see java.util.Observable#clearChanged()
* @see java.util.Observable#hasChanged()
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
public void notifyObservers() {
notifyObservers(null);
}
中介者模式
智能家庭管理问题
智能家庭项目:
- 智能家庭包括各种设备,闹钟、咖啡机、电视机、窗帝等
- 主人要看电视时,各个设备可以协同工作,自动完成看电视的准备工作,比如流
程为:闹铃响起-→>咖啡机开始做咖啡→窗帘自动落下->电视机开始播放
基本介绍
中介者(Mediator)模式的定义:定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。中介者模式又叫调停模式,它是迪米特法则的典型应用。
中介者模式包含以下主要角色。
- 抽象中介者(Mediator)角色:它是中介者的接口,提供了同事对象注册与转发同事对象信息的抽象方法。
- 具体中介者(Concrete Mediator)角色:实现中介者接口,定义一个 List 来管理同事对象,协调各个同事角色之间的交互关系,因此它依赖于同事角色。
- 抽象同事类(Colleague)角色:定义同事类的接口,保存中介者对象,提供同事对象交互的抽象方法,实现所有相互影响的同事类的公共功能。
- 具体同事类(Concrete Colleague)角色:是抽象同事类的实现者,当需要与其他同事对象交互时,由中介者对象负责后续的交互。
应用实例
// 抽象同事类(Colleague)角色
public interface Colleague {
// 接收消息
void receive();
// 发送消息
void send();
}
// 具体同事类
class ConcreteColleague1 implements Colleague {
Mediator mediator;
public ConcreteColleague1(Mediator mediator) {
this.mediator = mediator;
}
@Override
public void receive() {
System.out.println("具体同事类1收到请求。");
}
@Override
public void send() {
System.out.println("具体同事类1发出请求。");
// 请中介者转发
mediator.relay(this);
}
}
// 抽象中介者(Mediator)角色
public interface Mediator {
// 把同事类添加到集合中
void add(Colleague colleague);
// 转发
void relay(Colleague colleague);
}
// 具体中介者(Concrete Mediator)角色
class ConcreteMediator implements Mediator {
// 集合管理所有同事类
List<Colleague> list = new ArrayList<>();
@Override
public void add(Colleague colleague) {
list.add(colleague);
}
@Override
public void relay(Colleague colleague) {
for (Colleague colleague1 : list) {
if (colleague1.equals(colleague)) {
colleague1.receive();
}
}
}
}
class Client {
public static void main(String[] args) {
// 创建中介者
Mediator mediator = new ConcreteMediator();
// 创建同事类
ConcreteColleague1 colleague1 = new ConcreteColleague1(mediator);
mediator.add(colleague1);
colleague1.send();
}
}
中介者的注意事项和细节
- 多个类相互耦合,会形成网状结构,使用中介者模式将网状结构分离为星型结构,进行解耦
- 减少类间依赖,降低了耦合,符合迪米特原则
- 中介者承担了较多的责任,一旦中介者出现了问题,整个系统就会受到影响如果设计不当,中介者对象本身变得过于复杂,这点在实际使用时,要特别注意
备忘录模式
游戏角色状态恢复问题
游戏角色状态恢复问题
游戏角色有攻击力和防御力,在大战Boss前保存自身的状态(攻击力和防御力),当大战Boss后攻击力和防御力下降,从备忘录对象恢复到大战前的状态
基本介绍
1)备忘录模式(Memento Pattern)在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态
2)可以这里理解备忘录模式:现实生活中的备忘录是用来记录某些要去做的事情,或者是记录已经达成的共同意见的事情,以防忘记了。而在软件层面,备忘录模式有着相同的含义,备忘录对象主要用来记录一个对象的某种状态,或者某些数据,当要做回退时,可以从备忘录对象里获取原来的数据进行恢复操作
3)备忘录模式属于行为型模式
备忘录模式的主要角色如下。
- 发起人(Originator)角色:记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
- 备忘录(Memento)角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。
- 管理者(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。
应用实例
// 备忘录(Memento)角色
@Data
public class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
}
// 发起人(Originator)角色
@Data
public class Originator {
private String state;
// 获取备忘录
public Memento getMementoState() {
return new Memento(state);
}
// 恢复状态
public void restoreMementoState(Memento memento) {
state = memento.getState();
}
}
// 管理者(Caretaker)角色
public class Caretaker {
// 备忘录集合
List<Memento> mementos = new ArrayList<>();
// 保存备忘录
void add(Memento memento) {
mementos.add(memento);
}
// 获取备忘录
Memento get(int index) {
return mementos.get(index);
}
}
// 客户端
class Client {
public static void main(String[] args) {
// 创建发起者
Originator originator = new Originator();
originator.setState("1");
// 创建备忘录
Memento mementoState = originator.getMementoState();
// 创建管理者 保存备忘录
Caretaker caretaker = new Caretaker();
caretaker.add(mementoState);
// 当状态发生变化
originator.setState("2");
System.out.println(originator.toString());
// 恢复状态 获取备忘录
Memento memento = caretaker.get(0);
originator.restoreMementoState(memento);
System.out.println(originator.toString());
}
}
备忘录模式的注意事项和细节
- 给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态
- 实现了信息的封装,使得用户不需要关心状态的保存细节
- 如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存,这个需要注意
- 适用的应用场景:1、后悔药。2、打游戏时的存档。3、Windows里的ctri +z。4、正中的后退。4、数据库的事务管理
- 为了节约内存,备忘录模式可以和原型模式配合使用
解释器模式
四则运算问题
通过解释器模式来实现四则运算,如计算a+b-c的值,具体要求
1)先输入表达式的形式,比如 a+b+c-d+e,要求表达式的字母不能重复
2)在分别输入a ,b, c,d,e的值
3)最后求出结果:如图
基本介绍
1)在编译原理中,一个算术表达式通过 词法分析器 成词法单元,而后这些词法单元再通过 语法分析器 构建语法分析树,一颗抽象的语法分析树。这里的词法分析器和语法分析器都可以看做是解释器
2)解释器模式(Interpreter Pattern):是指给定一个语言表达式,定义它的文法的一种表示,并定义一个解释器>使用该解释器来解样语言中的句子(表达式)
3)应用场最
应用可以将一个需要解释执行的语言中的句子表示为一个抽象语法树
一些重复出现的问题可以用一种简单的语言来表达
一个简单语法需要解释的场景
4)这样的例子还有,比如编译器、运算表达式计算、正则表达式、机器人等
文法、句子、语法树
1) 文法
文法是用于描述语言的语法结构的形式规则。没有规矩不成方圆,例如,有些人认为完美爱情的准则是“相互吸引、感情专一、任何一方都没有恋爱经历”,虽然最后一条准则较苛刻,但任何事情都要有规则,语言也一样,不管它是机器语言还是自然语言,都有它自己的文法规则。例如,中文中的“句子”的文法如下。
〈句子〉::=〈主语〉〈谓语〉〈宾语〉
〈主语〉::=〈代词〉|〈名词〉
〈谓语〉::=〈动词〉
〈宾语〉::=〈代词〉|〈名词〉
〈代词〉你|我|他
〈名词〉7大学生I筱霞I英语
〈动词〉::=是|学习
注:这里的符号“::=”表示“定义为”的意思,用“〈”和“〉”括住的是非终结符,没有括住的是终结符。
2) 句子
句子是语言的基本单位,是语言集中的一个元素,它由终结符构成,能由“文法”推导出。例如,上述文法可以推出“我是大学生”,所以它是句子。
3) 语法树
语法树是句子结构的一种树型表示,它代表了句子的推导结果,它有利于理解句子语法结构的层次。图 1 所示是“我是大学生”的语法树。
解释器模式结构
解释器模式包含以下主要角色。
- 抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()。
- 终结符表达式(Terminal Expression)角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。
- 非终结符表达式(Nonterminal Expression)角色:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。
- 环境(Context)角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。
- 客户端(Client):主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法。
应用实例
/**
* 抽象表达式(Abstract Expression)角色
* <p>
* 通过hashMap键值对,key获取到变量的值
* </p>
* @author tuxuchen
* @date 2022/6/13 14:53
*/
public abstract class Expression {
/**
* a + b - c
* <p>
* 解释公式 key就是公式(表达式) 参数[a,b,c] value就是具体的值
* hashMap{a=10, b=20}
* </p>
* @param var
*/
abstract Integer interpret(Map<String, Integer> var);
}
/**
* 终结符表达式(Terminal Expression)角色
* <p>
* 变量的解释器
* </p>
* @author tuxuchen
* @date 2022/6/13 14:57
*/
public class VarExpression extends Expression {
private String key; // key=a,key=b,key=c
public VarExpression(String key) {
this.key = key;
}
/**
* 根据变量名称 返回对应的值
* @param var
* @return
*/
@Override
Integer interpret(Map<String, Integer> var) {
return var.get(this.key);
}
}
/**
* 非终结符表达式(Nonterminal Expression)角色
* <p>
* 抽象运算符号解析器 每个运算符都只和自己左右两个数字有关系
* 但左右两个数字有可能也是一个解析的结果 无论是何种类型 都是Expression类的实现类
* </p>
* @author tuxuchen
* @date 2022/6/13 15:03
*/
public class SymbolExpression extends Expression {
protected Expression left;
protected Expression right;
public SymbolExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
// SymbolExpression 具体是让子类实现 此处是空实现
@Override
Integer interpret(Map<String, Integer> var) {
return null;
}
}
// 加法
class AddExpression extends SymbolExpression {
public AddExpression(Expression left, Expression right) {
super(left, right);
}
// 表达式左右相加
@Override
Integer interpret(Map<String, Integer> var) {
return super.left.interpret(var) + super.right.interpret(var);
}
}
// 减法
class SubExpression extends SymbolExpression {
public SubExpression(Expression left, Expression right) {
super(left, right);
}
// 表达式左右相减
@Override
Integer interpret(Map<String, Integer> var) {
return super.left.interpret(var) - super.right.interpret(var);
}
}
/**
* 环境(Context)角色
* <P>
* 通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。
* </P>
* @author tuxuchen
* @date 2022/6/13 15:16
*/
public class Calculator {
// 定义表达式
private Expression expression;
Calculator(String expStr) {
// 安排运算的先后顺序
Stack<Expression> stack = new Stack<>();
// 表达式拆分成字符串数组 [a,+,b]
char[] charArray = expStr.toCharArray();
Expression left = null;
Expression right = null;
// 遍历字符串数组 [a,+,b]
for (int i = 0; i < charArray.length; i++) {
switch (charArray[i]) {
case '+':
left = stack.pop(); // 从Stack 取出left => a
right = new VarExpression(String.valueOf(charArray[++i]));// 取出右表达式 right => b
stack.push(new AddExpression(left, right));
break;
case '-':
left = stack.pop();
right = new VarExpression(String.valueOf(charArray[++i]));
stack.push(new SubExpression(left, right));
break;
default:
stack.push(new VarExpression(String.valueOf(charArray[i])));
break;
}
}
// 遍历完表达式以后 就得到了 最终的Expression
this.expression = stack.pop();
}
public int run(Map<String, Integer> var) {
return this.expression.interpret(var);
}
}
// 客户端
class Client {
public static void main(String[] args) {
String expStr = "a+b-c";
Map<String, Integer> map = new HashMap<>();
map.put("a", 10);
map.put("b", 20);
map.put("c", 5);
Calculator calculator = new Calculator(expStr);
int run = calculator.run(map);
System.out.println(run);
}
}
解释器模式的注意事项和细节
当有一个语言需要解释执行,可将该语言中的句子表示为一个抽象语法树
就可以考虑使用解释器模式,让程序具有良好的扩展性
应用场景:编译器、运算表达式计算、正则表达式、机器人等
使用解释器可能带来的间题:解释器模式会引起类膨胀、解释器模式采用递归调用方法,将会导致调试非常复杂、效率可能降低.
状态模式
APP抽奖活动
请编写程序完成APP抽奖活动具体要求如下:
1)假如每参加一次这个活动要
扣陈用户50积分,中奖概率是10%
2)奖品数量固定,抽完就不能
抽奖
3)活动有四个状态:可以抽奖、
不能抽奖、发放奖品和奖品领完
4)活动的四个状态转换关系图
基本介绍
状态模式(State Pattern):它主要用来解决对象在多种状态转换时,需要对外输出不同的行为的问题。状态和行为是一—对应的,状态之间可以相互转换当一个对象的内在状态改变时,继许改变其行为,这个对象看起来像是改变了其类
状态模式包含以下主要角色。
- 环境类(Context)角色:也称为上下文,它定义了客户端需要的接口,内部维护一个当前状态,并负责具体状态的切换。
- 抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为,可以有一个或多个行为。
- 具体状态(Concrete State)角色:实现抽象状态所对应的行为,并且在需要的情况下进行状态切换。
应用实例
public class StatePatternClient {
public static void main(String[] args) {
Context context = new Context(); //创建环境
context.Handle(); //处理请求
context.Handle();
context.Handle();
context.Handle();
}
}
//环境类
class Context {
private State state;
//定义环境类的初始状态
public Context() {
this.state = new ConcreteStateA();
}
//设置新状态
public void setState(State state) {
this.state = state;
}
//读取状态
public State getState() {
return (state);
}
//对请求做处理
public void Handle() {
state.Handle(this);
}
}
//抽象状态类
abstract class State {
public abstract void Handle(Context context);
}
//具体状态A类
class ConcreteStateA extends State {
public void Handle(Context context) {
System.out.println("当前状态是 A.");
context.setState(new ConcreteStateB());
}
}
//具体状态B类
class ConcreteStateB extends State {
public void Handle(Context context) {
System.out.println("当前状态是 B.");
context.setState(new ConcreteStateA());
}
}
状态模式的注意事项和细节
代码有很强的可读性。状态模式将每个状态的行为封装到对应的一个类中
方便维护。将容易产生问题的if-else语句删除了,如果把每个状态的行为都放到一个类中,每次调用方法时都要判断当前是什么状态,不但会产出很多if-else语句,而且容易出错
符合“开闭原则”。容易增删状态
会产生很多类。每个状态都要一个对应的类,当状态过多时会产生很多类,加大维护难度
当一个事件或者对象有很多种状态,状态之间会相互转换,对不同的状态要求有不同的行为的时候,可以考虑使用状态模式
策略模式
鸭子项目
编写鸭子项目,具体要求如下:
1)有各种鸭子(比如野鸭、北京鸭、水鸭等,鸭子有各种行为,比如叫、飞行等)
2)显示鸭子的信息
基本介绍
策略模式是准备一组算法,并将这组算法封装到一系列的策略类里面,作为一个抽象策略类的子类。策略模式的重心不是如何实现算法,而是如何组织这些算法,从而让程序结构更加灵活,具有更好的维护性和扩展性,现在我们来分析其基本结构和实现方法。
策略模式的主要角色如下。
- 抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
- 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。
- 环境(Context)类:持有一个策略类的引用,最终给客户端调用。
应用实例
// 抽象策略(Strategy)类
public interface FlyBehavior {
void fly();
}
// 具体策略(Concrete Strategy)类
class GoodFlyBehavior implements FlyBehavior {
@Override
public void fly() {
System.out.println("飞行继续非常好");
}
}
// 具体策略(Concrete Strategy)类
class NoFlyBehavior implements FlyBehavior {
@Override
public void fly() {
System.out.println("不会飞行");
}
}
// 环境类
@Data
public abstract class Duck {
private FlyBehavior flyBehavior;
abstract void display(); // 显示鸭子信息
void fly() {
flyBehavior.fly();
}
}
class WildDuck extends Duck {
public WildDuck() {
GoodFlyBehavior behavior = new GoodFlyBehavior();
setFlyBehavior(behavior);
}
@Override
void display() {
System.out.println("野鸭");
}
}
class PekingDuck extends Duck {
public PekingDuck() {
NoFlyBehavior behavior = new NoFlyBehavior();
setFlyBehavior(behavior);
}
@Override
void display() {
System.out.println("北京鸭");
}
}
// 客户端
class Client {
public static void main(String[] args) {
Duck duck = new WildDuck();
duck.display();
duck.fly();
}
}
策略模式的注意事项和细节
策略模式的关键是:定析项目中交化部分与不变部分
策略模式的核心思想是:多用组合/聚合少用继承:用行为类组合,而不是行为的继承。更有弹性
体现了“对修改关闭,对扩展开放”原则,客户端增加行为不用修改原有代码,只要添加一种策略(或者行为)即可,避免了使用多重转移语句(it.else if…else)提供了可以替换继承关系的办法:策略模式将算法封装在独立的Strategy类中使得你可以建立于其Context改变它,使它易于切换、易于理解、易于扩展
需要注意的是:每添加一个策略就要增加一个类,当策略过多是会导致类数目庞大
责任链模式
OA系统采购审批需求
学校OA系统的彩购审批项目:需求是
1)采购员采购教学器材
2)如果金额小于等于5000,由教学主任审批
3)如果金额小于等于10000,由院长审批
4)如果金额小于等于30000,由副校长市批
5)如果金额超过30000以上,有校长审批请设计程序完或采购审批项目
基本介绍
职责链模式(Chain of Responsibility Pattern) ,又叫责任链模式,为请求创建了个接收者对象的链(简单示意图)。这种模式对请求的发送者和接收者进行解耦。
职责链模式通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
这种类型的设计模式属于行为型模式
职责链模式主要包含以下角色。
- 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
- 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
- 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
应用实例
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PurChaseRequest {
private int id = 0; // 请求编号
private int type;
private float price = 0.0f; // 请求金额
}
// 抽象处理者(Handler)角色
public abstract class Approver {
Approver approver; //下一个处理者
String name;
Approver(String name) {
this.name = name;
}
// 设置下一个处理者
void setApprover(Approver approver) {
this.approver = approver;
}
// 处理请求方法
abstract void processRequest(PurChaseRequest purChaseRequest);
}
// 具体处理者(Concrete Handler)角色
class DepartmentApprover extends Approver {
DepartmentApprover(String name) {
super(name);
}
@Override
void processRequest(PurChaseRequest purChaseRequest) {
if (purChaseRequest.getPrice() <= 5000) {
System.out.println("处理编号:" + purChaseRequest.getId() + ",处理人:" + name);
} else {
purChaseRequest.setId(0);
approver.processRequest(purChaseRequest); // 交给下一个处理器 处理
}
}
}
class CollegeApprover extends Approver {
CollegeApprover(String name) {
super(name);
}
@Override
void processRequest(PurChaseRequest purChaseRequest) {
if (purChaseRequest.getPrice() > 5000 && purChaseRequest.getPrice() <= 10000 ) {
System.out.println("处理编号:" + purChaseRequest.getId() + ",处理人:" + name);
} else {
purChaseRequest.setId(1);
approver.processRequest(purChaseRequest); // 交给下一个处理器 处理
}
}
}
// 客户端
class Client {
public static void main(String[] args) {
DepartmentApprover departmentApprover = new DepartmentApprover("小张");
CollegeApprover collegeApprover = new CollegeApprover("小王");
// 设置下一审批人
departmentApprover.setApprover(collegeApprover);
// 需要处理的数据
PurChaseRequest request = new PurChaseRequest();
departmentApprover.processRequest(request);
}
}
责任链模式的注意事项和细节
- 将请求和处理分开,实现解耦,提高系统的灵活性简化了对象,使对象不需要知道链的结构
- 性能会受到影响,特别是在链比较长的时候,因此需控制链中最大节点数量,一般通过在
Handler
中设置一个最大节点数量,在setNext()
方法中判断是否已经超过阀值超过则不允许该链建立,避免出现超长链无意识地破坏系统性能 - 调试不方便。采用了类似递归的方式,调试时逻辑可能比较复杂
- 最佳应用场景:有多个对象可以处理同一个请求时,比如:多级请求、请假/加薪等审批流程、Java Web中Tomcat对Encoding的处理、拦截器
归纳设计模式
创建型设计模式(简单来说就是用来创建对象的)
设计模式 | 简述 | 一句话归纳 | 目的 | 生活案例 |
---|---|---|---|---|
工厂模式(Factory Pattern) | 不同条件下创建不同实例 | 产品标准化,生产更高效 | 封装创建细节 | 实体工厂 |
单例模式(Singleton Pattern) | 保证一个类仅有一个实例,并且提供一个全局访问点 | 世上只有一个我 | 保证独一无二 | CEO |
原型模式(Prototype Pattern) | 通过拷贝原型创建新的对象 | 拔一根猴毛,吹出千万个 | 高效创建对象 | 克隆 |
建造者模式(Builder Pattern) | 用来创建复杂的复合对象 | 高配中配和低配,想选哪配就哪配 | 开放个性配置步骤 | 选配 |
结构型设计模式(关注类和对象的组合)
设计模式 | 简述 | 一句话归纳 | 目的 | 生活案例 |
---|---|---|---|---|
代理模式(Proxy Pattern) | 为其他对象提供一种代理以控制对这个对象的访问 | 没有资源没时间,得找别人来帮忙 | 增强职责 | 媒婆 |
外观模式(Facade Pattern) | 对外提供一个统一的接口用来访问子系统 | 打开一扇门,通向全世界 | 统一访问入口 | 前台 |
装饰器模式(Decorator Pattern) | 为对象添加新功能 | 他大舅他二舅都是他舅 | 灵活扩展、同宗同源 | 煎饼 |
享元模式(Flyweight Pattern) | 使用对象池来减少重复对象的创建 | 优化资源配置,减少重复浪费 | 共享资源池 | 全国社保联网 |
组合模式(Composite Pattern) | 将整体与局部(树形结构)进行递归组合,让客户端能够以一种的方式对其进行处理 | 人在一起叫团伙,心在一起叫团队 | 统一整体和个体 | 组织架构树 |
适配器模式(Adapter Pattern) | 将原来不兼容的两个类融合在一起 | 万能充电器 | 兼容转换 | 电源适配 |
桥接模式(Bridge Pattern) | 将两个能够独立变化的部分分离开来 | 约定优于配置 | 不允许用继承 | 桥 |
行为型设计模式(关注对象之间的通信)
设计模式 | 简述 | 一句话归纳 | 目的 | 生活案例 |
---|---|---|---|---|
模板模式(Template Pattern) | 定义一套流程模板,根据需要实现模板中的操作 | 流程全部标准化,需要微调请覆盖 | 逻辑复用 | 把大象装进冰箱 |
命令模式(Command Pattern) | 将请求封装成命令,并记录下来,能够撤销与重做 | 运筹帷幄之中,决胜千里之外 | 解耦请求和处理 | 遥控器 |
访问者模式(Visitor Pattern) | 稳定数据结构,定义新的操作行为 | 横看成岭侧成峰,远近高低各不同 | 解耦数据结构和数据操作 | KPI考核 |
迭代器模式(Iterator Pattern) | 提供一种方法顺序访问一个聚合对象中的各个元素 | 流水线上坐一天,每个包裹扫一遍 | 统一对集合的访问方式 | 逐个检票进站 |
观察者模式(Observer Pattern) | 状态发生改变时通知观察者,一对多的关系 | 到点就通知我 | 解耦观察者与被观察者 | 闹钟 |
中介者模式(Mediator Pattern) | 将对象之间的通信关联关系封装到一个中介类中单独处理,从而使其耦合松散 | 联系方式我给你,怎么搞定我不管 | 统一管理网状资源 | 朋友圈 |
备忘录模式(Memento Pattern) | 保存对象的状态,在需要时进行恢复 | 失足不成千古恨,想重来时就重来 | 备份、后悔机制 | 草稿箱 |
解释器模式(Interpreter Pattern) | 给定一个语言,定义它的语法表示,并定义一个解释器,这个解释器使用该标识来解释语言中的句子 | 我想说”方言“,一切解释权都归我 | 实现特定语法解析 | 摩斯密码 |
状态模式(State Pattern) | 根据不同的状态做出不同的行为 | 状态驱动行为,行为决定状态 | 绑定状态和行为 | 订单状态跟踪 |
策略模式(Strategy Pattern) | 封装不同的算法,算法之间能互相替换 | 条条大道通罗马,具体哪条你来定 | 把选择权交给用户 | 选择支付方式 |
责任链模式(Chain of Responsibility Pattern) | 拦截的类都实现统一接口,每个接收者都包含对下一个接收者的引用。将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。 | 各人自扫门前雪,莫管他们瓦上霜 | 解耦处理逻辑 | 踢皮球 |
参考文档:地址
参考视频:尚硅谷23种设计模式