外观模式 :
迪米特法则(最少知识原则) : 一个软件实体应当尽可能少的与其他实体发送相互作用.
外观模式核心 : 为子系统提高统一的入口,封装子系统的复杂性,便于客户端调用.
开发中常见的场景 :
频率很高.哪里都会遇到.各种技术和框架中,都有外观模式的使用.如 : JDBC封装后的,commons提供的DBUtils类,Hibernate提供的工具类,Spring JDBC工具类等.
享元模式(FlyWeight) :
场景 : 内存属于稀缺资源,不要随便浪费.如果有很多个完全相同或相似的对象,我们可以通过享元模式,节省内存.
核心 : 享元模式以共享的方式高效的支持大量细粒度对象的重用.
享元模式能做到共享的关键和区分了内部状态和外部状态.
内部状态 : 可以共享,不会随环境变化而改变.
外部状态 : 不可以共享,会随环境变化而改变.
享元模式实现 :
FlyweightFactory享元工厂类 : 创建并管理享元对象,享元池一般设计成键值对.
FlyWeight抽象享元类 : 通常是一个接口或抽象类,声明公共方法,这些方法可以向外界提供对象的内部状态,设置外部状态.
ConcreteFlyWeight具体享元类 : 为内部状态提供成员变量进行存储.
UnsharedConcreteFlyWeight非共享享元类 : 不能被共享的子类可以设计为非共享享元类.
享元模式开发中应用的场景 :
享元模式由于其共享的特性,可以再任何'池'中操作,比如 : 线程池,数据库连接池.String类的设计也是享元模式.
优点 :
极大减少内存中对象的数量;
相同或相似对象内存中只存一份,极大的节约资源,提供系统性能;
外部状态相对独立,不影响内部状态.
缺点 :
模式较复杂,使程序逻辑复杂化;
为了节省内存,共享了内部状态,分离出外部状态,而读取外部状态使运行时间变长.用时间换取了空间.
例子 :
package com.example.demo.flyweight;
/**
* 享元类
*/
public interface ChessFlyWeight {
void setColor(String c);
String getColor();
void display(Coordinate c);
}
class ConcreteChess implements ChessFlyWeight {
private String color;
public ConcreteChess(String color) {
this.color = color;
}
@Override
public void setColor(String c) {
this.color = c;
}
@Override
public String getColor() {
return color;
}
@Override
public void display(Coordinate coordinate) {
System.out.println("棋子颜色 : " + color);
System.out.println("棋子位置 : " + coordinate.getX() + "-----" + coordinate.getY());
}
}
package com.example.demo.flyweight;
import java.util.HashMap;
import java.util.Map;
/**
* 享元工厂类
*/
public class ChessFlyWeightFactory {
// 享元池
private static Map<String, ChessFlyWeight> map = new HashMap<>();
public static ChessFlyWeight getChess(String color) {
if (map.get(color) != null) {
return map.get(color);
} else {
ChessFlyWeight cfw = new ConcreteChess(color);
map.put(color, cfw);
return cfw;
}
}
}
package com.example.demo.flyweight;
/**
* 外部状态UnSharedConcreteFlyWeight
*/
public class Coordinate {
private int x,y;
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
package com.example.demo.flyweight;
public class Client {
public static void main(String[] args) {
ChessFlyWeight chess1 = ChessFlyWeightFactory.getChess("黑色");
ChessFlyWeight chess2 = ChessFlyWeightFactory.getChess("黑色");
System.out.println(chess1);
System.out.println(chess2);
System.out.println("增加外部状态的处理======");
chess1.display(new Coordinate(10, 10));
chess2.display(new Coordinate(20, 20));
}
}
结构型模式汇总 :
代理模式 : 为真实对象提供一个代理,从而控制对真实对象的访问;
适配模式 : 使原本由于接口不兼容不能一起工作的类可以一起工作;
桥接模式 : 处理多层继承结构,处理多维度变化的场景,将各个维度设计成独立的继承结构,使各个维度可以独立的扩展在抽象层建立关联.
组合模式 : 将对象组合成树状结构以表示"部分和整体"层次结构,使得客户可以统一的调用叶子对象和容器对象.
装饰模式 : 动态的给一个对象添加额外的功能,比继承灵活.
外观模式 : 为子系统提供统一的调用接口,使得子系统更加容易使用.
享元模式 : 运用共享技术有效的实现管理大量细粒度对象,节省内存,提供效率.
创建型模式关注对象的创建过程.
结构型模式关注对象和类的组织.
行为型模式 :
关注系统中对象之间的相互交互,研究系统在运行时对象之间 的相互通信和协作,进一步明确对象的职责,共有11种模式.
行为型模式汇总 :
(1) 责任链模式 chain of responsibility
(2) 命令模式 command
(3) 解释器模式 interpreter
(4) 迭代器模式 iterator
(5) 中介者模式 mediator
(6) 备忘录模式 memento
(7) 观察者模式 observer
(8) 状态模式 state
(9) 策略模式 strategy
(10) 模板方法模式 template method
(11) 访问者模式 visitor
责任链模式(chain or responsibility) :
定义 : 将能够处理同一类请求的对象连成一条链,所提交的请求沿着链传递,链上的对象逐个判断是否有能力处理该请求,如果能则处理,如果不能则传递给链上的下一个对象.
场景 :
打牌时,轮流出牌;接力赛跑;大学中,奖学金审批;公司中,公文审批;
添加新的处理对象 :
由于责任链的创建完成在客户端,因此新增新的具体处理这对原有类库没有任何影响,只需添加新的类,然后再客户端调用时添加即可.符合开闭原则.
链表方式定义责任链 :
非链表方式实现责任链 : 通过集合,数组生成责任链更加实用!实际上,很多项目中,每个具体的Handler并不是开发团队定义的,而是项目上线后由外部单位追加的,
所以使用链表方式订阅COR链就很困难.
开发中常见的场景 :
Java中,异常机制就是一种责任链模式.一个try可以对应多个catch,当第一个catch不匹配类型,则自动跳到第二个catch.
JavaScript语言中,事件的冒泡和捕获机制.Java语言中,事件的处理采用观察者模式.
Servlet开发中,过滤器的链式处理.
Struts2中,拦截器的调用也是典型的责任链模式.
例子中 :
package com.example.demo.chainOfResp;
/**
* 封装请假的基本信息
*/
public class LeaveRequest {
private String empName;
private int leaveDays;
private String reason;
public LeaveRequest(String empName, int leaveDays, String reason) {
super();
this.empName = empName;
this.leaveDays = leaveDays;
this.reason = reason;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public int getLeaveDays() {
return leaveDays;
}
public void setLeaveDays(int leaveDays) {
this.leaveDays = leaveDays;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
}
package com.example.demo.chainOfResp;
/**
* 主任
*/
public class Director extends Leader {
public Director(String name) {
super(name);
}
@Override
public void handleRequest(LeaveRequest request) {
if (request.getLeaveDays() < 3) {
System.out.println("员工 : " + request.getEmpName() + "请假,天数 : " + request.getLeaveDays() + ", 理由 : " + request.getReason());
System.out.println("主任 : " + this.name + ", 审批通过!");
} else {
if (this.nextLeader != null) {
this.nextLeader.handleRequest(request);
}
}
}
}
package com.example.demo.chainOfResp;
/**
* 副总
*/
public class ViceGeneralManager extends Leader {
public ViceGeneralManager(String name) {
super(name);
}
@Override
public void handleRequest(LeaveRequest request) {
if (request.getLeaveDays() < 60) {
System.out.println("员工 : " + request.getEmpName() + "请假,天数 : " + request.getLeaveDays() + ", 理由 : " + request.getReason());
System.out.println("总经理 : " + this.name + ", 审批通过!");
} else {
System.out.println("无法申请请假!");
}
}
}
package com.example.demo.chainOfResp;
public class GeneralManager extends Leader {
public GeneralManager(String name) {
super(name);
}
@Override
public void handleRequest(LeaveRequest request) {
if (request.getLeaveDays() < 30) {
System.out.println("员工 : " + request.getEmpName() + "请假,天数 : " + request.getLeaveDays() + ", 理由 : " + request.getReason());
System.out.println("总经理 : " + this.name + ", 审批通过!");
} else {
if (this.nextLeader != null) {
this.nextLeader.handleRequest(request);
}
}
}
}
package com.example.demo.chainOfResp;
/**
* 抽象类
*/
public abstract class Leader {
protected String name;
// 责任链上后继对象
protected Leader nextLeader;
public Leader(String name) {
this.name = name;
}
// 设定责任链上的后继对象
public void setNextLeader(Leader nextLeader) {
this.nextLeader = nextLeader;
}
/**
* 处理请求的核心的业务方法
*/
public abstract void handleRequest(LeaveRequest request);
}
package com.example.demo.chainOfResp;
/**
* 经理
*/
public class Manager extends Leader {
public Manager(String name) {
super(name);
}
@Override
public void handleRequest(LeaveRequest request) {
if (request.getLeaveDays() < 10) {
System.out.println("员工 : " + request.getEmpName() + "请假,天数 : " + request.getLeaveDays() + ", 理由 : " + request.getReason());
System.out.println("经理 : " + this.name + ", 审批通过!");
} else {
if (this.nextLeader != null) {
this.nextLeader.handleRequest(request);
}
}
}
}
package com.example.demo.chainOfResp;
public class Client {
public static void main(String[] args) {
Leader a = new Director("张三");
Leader b = new Manager("李四");
Leader c = new GeneralManager("王五");
Leader d = new ViceGeneralManager("张强");
// 组织责任链对象的关系
a.setNextLeader(b);
b.setNextLeader(c);
c.setNextLeader(d);
// 开始请假操作
LeaveRequest request = new LeaveRequest("TOM", 30, "回家");
a.handleRequest(request);
}
}
迭代器模式(iterator)
场景 :
提供一种可以遍历聚合对象的方式.又称为 : 游标cursor模式;
聚合对象 : 存储数据;
迭代器 : 遍历数据
基本案例 :
实现正向遍历的迭代器;
实现逆向遍历的迭代器;
开发中常见的场景 :
JDK内置的迭代器(List/Set)
例子 :
package com.example.demo.iterator;
/**
* 自定义的迭代器接口
*/
public interface MyIterator {
// 将游标指向第一个元素
void first();
// 将游标指向下一个元素
void next();
// 判断是否存在下一个元素
boolean hasNext();
boolean isFirst();
boolean isLast();
// 获取当前游标指向的对象
Object getCurrentObj();
}
package com.example.demo.iterator;
import java.util.ArrayList;
import java.util.List;
/**
* 自定义的聚合类
*/
public class ConcreteMyAggregate {
private List<Object> list = new ArrayList<Object>();
public ConcreteMyAggregate() {
super();
}
public void addObject(Object obj) {
this.list.add(obj);
}
public void removeObject(Object obj) {
this.list.remove(obj);
}
public List<Object> getList() {
return list;
}
public void setList(List<Object> list) {
this.list = list;
}
// 获得迭代器
public MyIterator createIterator() {
return new ConcreteIterator();
}
// 使用内部类订阅迭代器,可以直接使用外部类的属性
private class ConcreteIterator implements MyIterator {
// 定义游标用于记录遍历时的位置
private int cursor;
@Override
public void first() {
cursor = 0;
}
@Override
public void next() {
if (cursor < list.size()) {
cursor++;
}
}
@Override
public boolean hasNext() {
if (cursor < list.size()) {
return true;
}
return false;
}
@Override
public boolean isFirst() {
return cursor == 0 ? true : false;
}
@Override
public boolean isLast() {
return cursor == (list.size() - 1) ? true : false;
}
@Override
public Object getCurrentObj() {
return list.get(cursor);
}
}
}
package com.example.demo.iterator;
public class Client {
public static void main(String[] args) {
ConcreteMyAggregate cma = new ConcreteMyAggregate();
cma.addObject("aa");
cma.addObject("bb");
cma.addObject("cc");
MyIterator iterator = cma.createIterator();
while (iterator.hasNext()) {
System.out.println(iterator.getCurrentObj());
iterator.next();
}
}
}
中介者模式(Mediator) :
核心 :
如果一个系统中对象之间的联系呈现为网状结构,对象之间存在大量多对多关系,将导致关系及其复杂,这些对象称为"同事对象";
我们可以引入一个中介者对象,使各个同事对象只跟中介者对象打交道,将复杂的网络结构化解为星形结构.
中介者模式的本质 :
解耦多个同事对象之间的交互关系.每个对象都持有中介者对象的引用,只跟中介者对象打交道.我们通过中介者对象统一管理这些交互关系.
开发中常见的场景 :
MVC模式(其中的C,控制器就是一个中介者对象.M和V都和他打交道);
窗口游戏程序,窗口软件开发中窗口对象也是一个中介者对象;
图像界面开发GUI中,多个组件之间的交互,可以通过引入一个中介者对象来解决,可以是整体的窗口对象或者DOM对象.
Java.lang.reflect.Method#invoke()
例子 :
package com.example.demo.mediator;
// 中介者
public interface Mediator {
void register(String dname, Department d);
void command(String dname);
}
package com.example.demo.mediator;
import java.util.HashMap;
import java.util.Map;
public class President implements Mediator {
private Map<String, Department> map = new HashMap<>();
@Override
public void register(String dname, Department d) {
map.put(dname, d);
}
@Override
public void command(String dname) {
map.get(dname);
}
}
package com.example.demo.mediator;
// 同事类的接口
public interface Department {
// 做本部门的事情
void selfAction();
// 向总经理发出申请
void outAction();
}
package com.example.demo.mediator;
public class Development implements Department {
// 持有中介者的引用
private Mediator m;
public Development(Mediator m) {
this.m = m;
m.register("development", this);
}
@Override
public void selfAction() {
System.out.println("汇报工作!没钱了,需要资金支持!");
}
@Override
public void outAction() {
System.out.println("专心科研,开发项目!");
}
}
package com.example.demo.mediator;
public class Finacial implements Department {
// 持有中介者(总经理)的引用
private Mediator m;
public Finacial(Mediator m) {
this.m = m;
m.register("finacial", this);
}
@Override
public void selfAction() {
System.out.println("汇报工作!没钱了,钱太多了!怎么花?");
}
@Override
public void outAction() {
System.out.println("数钱!");
}
}
package com.example.demo.mediator;
public class Market implements Department {
// 持有中介者(总经理)的引用
private Mediator m;
public Market(Mediator m) {
this.m = m;
m.register("market", this);
}
@Override
public void selfAction() {
System.out.println("汇报工作!项目承接的进度,需要资金支持!");
}
@Override
public void outAction() {
System.out.println("跑去接项目!");
m.command("finacial");
}
}
package com.example.demo.mediator;
public class Client {
public static void main(String[] args) {
Mediator m = new President();
Market market = new Market(m);
Development development = new Development(m);
Finacial finacial = new Finacial(m);
market.selfAction();
market.outAction();
}
}
命令模式(command) :
介绍 :
命令模式 : 将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作.也称之为 : 动作
Action模式,事务transaction模式;
结构 :
Command抽象命令类;
ConcreteCommand具体命令类;
Invoker调用者/请求者 :
请求的发送者,它通过命令对象来执行请求.一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联.在程序运行时,将调用命令对象的
execute(),间接调用接收者的相关操作.
Receiver接收者 :
接收者执行与请求相关的操作,具体实现对请求的业务处理.
未抽象前,实际执行操作内容的对象.
Client客户类 :
在客户类中需要创建调用者对象,具体命令类对象,在创建具体命令对象时指定对应的接收者.发送者和接收者之间没有直接关系,都通过命令对象间接调用.
开发中常见的场景 :
Struts2,action的整个调用过程中就有命令模式.
数据库事务机制的底层实现;
命令的撤销和恢复.
例子 :
package com.example.demo.command;
/**
* 真正的命令的执行者
*/
public class Receiver {
public void action() {
System.out.println("Receiver.action()");
}
}
package com.example.demo.command;
public interface Command {
/**
* 这个方法是一个返回结果为空的方法.
* 实际项目中,可以根据需求设计多个不同的方法
*/
void execute();
}
class ConcreteCommand implements Command {
// 命令的真正执行者
private Receiver receiver;
public ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
// 命令真正执行前或后,执行相关的处理!
receiver.action();
}
}
package com.example.demo.command;
/**
* 调用者/发起者
*/
public class Invoke {
// 也可以通过容器List<Command>容纳很多命令对象,进行批处理.数据库底层的事务管理就是类似的结构!
private Command command;
public Invoke(Command command) {
this.command = command;
}
// 业务方法,用于调用命令类的方法
public void call() {
command.execute();
}
}
package com.example.demo.command;
public class Client {
public static void main(String[] args) {
Command command = new ConcreteCommand(new Receiver());
Invoke invoke = new Invoke(command);
invoke.call();
}
}
解释器模式(Interpreter)
介绍 :
是一种不常用的设计模式;
用于描述如何构成一个简单的语言解释器,主要用于使用面向对象语言开发的编译器和解释器设计.
当我们需要开发一种新的语言时,可以考虑使用解释器模式.
尽量不要使用解释器模式,后期维护会有很大麻烦.在项目中,可以使用Jruby,Groovy,java的js引擎来替代解释器的作用,弥补java语言的不足.
开发中常见的场景 :
EL表达式的处理;正则表达式的解释器;SQL语法的解释器;数学表达式解释器;如现成的工具包 : Math Expression String Parser ,Expression4J等.
MESP的网址 :
Expression4J的网址 :
访问者模式Visitor :
模式动机 :
对于存储在一个集合中的对象,他们可能具有不同的类型(即使有一个公共的接口),对于该集合中的对象,可以接受一类称为访问者的对象来访问,不同的访问者其
访问方式也有所不同.
定义 :
表示一个作业于某个对象结构中的各元素的操作,它使我们可以在不改变个元素的类的前提下定义作业于这些元素的新操作.
开发中的场景(应用范围非常窄,了解即可) :
XML文档解析器设计;编译器的设计;复杂集合对象的处理;
策略模式 :
策略模式对应于解决某一个问题的一个算法族,允许用户从该算法族中任选一个算法解决某一问题,同时可以方便的更换算法或者增加新的算法.并且由客户端觉得调用哪个算法.
本质 :
分离算法,选择实现;
开发中常见的场景 :
JAVASE中GUI编程中,布局管理;Spring框架中,Resource接口,资源访问策略;javax.servlet.httpServlet#service();
例子 :
package com.example.demo.strategy;
public interface Strategy {
public double getPrice(double standardPrice);
}
package com.example.demo.strategy;
public class NewCustomerFewStrategy implements Strategy {
@Override
public double getPrice(double standardPrice) {
System.out.println("不打折,原价!");
return standardPrice;
}
}
package com.example.demo.strategy;
public class NewCustomerManyStrategy implements Strategy {
@Override
public double getPrice(double standardPrice) {
System.out.println("打九折!");
return standardPrice*0.9;
}
}
package com.example.demo.strategy;
public class OldCustomerManyStrategy implements Strategy {
@Override
public double getPrice(double standardPrice) {
System.out.println("打八折!");
return standardPrice*0.8;
}
}
package com.example.demo.strategy;
public class OldCustomerFewStrategy implements Strategy {
@Override
public double getPrice(double standardPrice) {
System.out.println("打八五折!");
return standardPrice*0.85;
}
}
package com.example.demo.strategy;
/**
* 负责和具体的策略类交互
* 这样的话,具体的算法和直接的客户端调用分离了,使得算法可以独立于客户端独立的变化
* 如果使用spring的依赖注入功能,换可以通过配置文件,动态的注入不同策略对象,动态的切换不同的算法.
*/
public class Context {
// 当前采用的算法对象
private Strategy strategy;
// 可以通过构造器来注入
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void pringPrice(double s) {
System.out.println("您该报价 : " + strategy.getPrice(s));
}
}
package com.example.demo.strategy;
public class Client {
public static void main(String[] args) {
Strategy s1 = new OldCustomerManyStrategy();
Context context = new Context(s1);
context.pringPrice(998);
}
}
模板方法模式(template method)
模板方法模式介绍 :
模板方法模式是编程中经常用得到模式.它定义了一个操作中的算法骨架,将某些步骤延迟到子类中实现.这样,新的子类可以在不改变一个算法结构的前提下重新
定义该算法的某些特定步骤.
核心 :
处理某个流程的代码已经都具备,但是其中某个节点的代码暂时不能确定.因此,我们采用工厂方法模式,将这个节点的代码实现转移给子类完成.既 : 处理步骤父类
中定义好,具体实现延迟到子类中定义.
方法回调(钩子方法)
在好莱坞,当艺人把简历提交给好莱坞的娱乐公司时,所能做的就是等待,整个过程由娱乐公司控制,演员只能被动的服务安排,在需要的时候再由公司安排具体环节的
演出.
在软件开发中,我们可以将call翻译为调用.子类不能调用父类,而通过父类调用子类.这些调用步骤已经在父类中写好了,完全由父类控制整个过程.
什么时候用到模板方法模式 :
实现一个算法时,整体步骤很固定.但是,某些部分易变.易变部分可以抽象出来,供子类实现.
开发中常见的场景 :
非常频繁.各个框架,类库中都有他的影子.比如常见的有 :
数据库访问的封装;Junit单元测试;servlet中关于doGet/doPost方法调用;Hibernate中模板程序;spring中JDBCTemplate,HibernateTemplate等.
例子 :
package com.example.demo.templateMethod;
public abstract class BankTemplateMethod {
// 具体方法
public void takeNumber() {
System.out.println("取号排队!");
}
// 办理具体的业务 //钩子方法
public abstract void transact();
public void evaluate() {
System.out.println("反馈评分");
}
// 模板方法,把基本操作组合到一起,子类一般不能重写.
public final void process() {
this.takeNumber();
// 像个钩子,执行时,挂那个子类的方法就调用哪个.
this.transact();
this.evaluate();
}
}
package com.example.demo.templateMethod;
public class client {
public static void main(String[] args) {
BankTemplateMethod bankTemplateMethod = new DrawMoney();
bankTemplateMethod.process();
System.out.println("----------------------");
// 采用匿名内部类
BankTemplateMethod bankTemplateMethod1 = new BankTemplateMethod() {
@Override
public void transact() {
System.out.println("我要存钱");
}
};
bankTemplateMethod1.process();
}
}
class DrawMoney extends BankTemplateMethod {
@Override
public void transact() {
System.out.println("我要取款!!!");
}
}
状态模式(state)
核心 : 用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题;
结构 : Context环境类(环境类中维护一个State对象,他是定义了当前的状态.);State抽象状态类;ConcreteState具体状态类(每一个类封装了一个状态对应的行为);
开发中常见的场景 :
银行系统中账号状态的管理;OA系统中公文状态的管理;酒店系统中,房间状态的管理;线程对象各状态之间的切换.
例子 :
package com.example.demo.state;
public interface State {
void handle();
}
package com.example.demo.state;
/**
* 空闲状态
*/
public class FreeState implements State{
@Override
public void handle() {
System.out.println("房间空闲!!!没人住.");
}
}
package com.example.demo.state;
/**
* 已预订状态
*/
public class BookedState implements State {
@Override
public void handle() {
System.out.println("房间已预订!别人不能定!");
}
}
package com.example.demo.state;
/**
* 已入住状态
*/
public class CheckedInState implements State {
@Override
public void handle() {
System.out.println("房间已入住!请勿打扰!");
}
}
package com.example.demo.state;
/**
* 方法对象
*/
public class Context {
// 如果是银行系统,这个Context类就是账号.根据金额不同,切换不同的状态!
private State state;
public void setState(State s) {
System.out.println("修改状态!");
state = s;
state.handle();
}
}
package com.example.demo.state;
public class Client {
public static void main(String[] args) {
Context context = new Context();
context.setState(new FreeState());
context.setState(new BookedState());
context.setState(new CheckedInState());
}
}
观察者模式(Observer) :
核心 :
观察者模式主要用于1 : N的通知.当一个对象(目标对象(消息发布)Subject或Objservable)的状态变化时,他需要及时告知一系列对象(观察者对象(消息订阅),Observer),令他们做出相应;
通知观察者的方式 :
推 : 每次都会把通知以广播方式发送给所有观察者,所有观察者只能被动接收.
拉 : 观察者只要直到有情况即可.至于什么时候获取内容,获取什么内容,都可以自主决定.
例子 :
package com.example.demo.observer;
public interface Observer {
void update(Subject subject);
}
package com.example.demo.observer;
import java.util.ArrayList;
import java.util.List;
public class Subject {
protected List<Observer> list = new ArrayList<>();
public void registerObserver(Observer obs) {
list.add(obs);
}
public void removeObserver(Observer obs) {
list.remove(obs);
}
//通知所有的观察者更新状态
public void notifyAllObservers() {
for (Observer observer : list) {
observer.update(this);
}
}
}
package com.example.demo.observer;
public class ObserverA implements Observer {
// myState需要跟目标对象的state值保存一致!
private int myState;
@Override
public void update(Subject subject) {
myState = ((ConcreteSubject)subject).getState();
}
public int getMyState() {
return myState;
}
public void setMyState(int myState) {
this.myState = myState;
}
}
package com.example.demo.observer;
public class ConcreteSubject extends Subject {
private int state;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
// 主题对象(目标对象)值发生了变化,请通知所有的观察者
this.notifyAllObservers();
}
}
package com.example.demo.observer;
public class Client {
public static void main(String[] args) {
// 目标对象
ConcreteSubject subject = new ConcreteSubject();
// 创建多个观察者
ObserverA obs1 = new ObserverA();
ObserverA obs2 = new ObserverA();
ObserverA obs3 = new ObserverA();
// 将这三个观察者添加到subject对象的观察者队伍中
subject.registerObserver(obs1);
subject.registerObserver(obs2);
subject.registerObserver(obs3);
// 改变subject的状态
subject.setState(3000);
// 我们看看,观察者的状态是不是也发生了变化
System.out.println(obs1.getMyState());
System.out.println(obs2.getMyState());
System.out.println(obs3.getMyState());
System.out.println("------------------");
// 改变subject的状态
subject.setState(30);
// 我们看看,观察者的状态是不是也发生了变化
System.out.println(obs1.getMyState());
System.out.println(obs2.getMyState());
System.out.println(obs3.getMyState());
}
}
JavaSE提供了java.util.Observable和java.util.Observer来实现观察者模式;
例子 :
package com.example.demo.observer2;
import java.util.Observable;
import java.util.Observer;
public class ObserverA implements Observer {
private int myState;
@Override
public void update(Observable o, Object arg) {
myState = ((ConcreteSubject) o).getState();
}
public int getMyState() {
return myState;
}
public void setMyState(int myState) {
this.myState = myState;
}
}
package com.example.demo.observer2;
import java.util.Observable;
public class ConcreteSubject extends Observable {
private int state;
public void set(int a) {
// 目标对象的状态发生了改变
state = a;
// 表示目标对象已经做了更改
setChanged();
// 通知所有的观察者
notifyObservers(state);
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
}
package com.example.demo.observer2;
public class Client {
public static void main(String[] args) {
// 创建目标对象Obserable
ConcreteSubject subject = new ConcreteSubject();
// 创建观察者
ObserverA observerA = new ObserverA();
ObserverA observerA1 = new ObserverA();
ObserverA observerA2 = new ObserverA();
// 将上面三个观察者对象添加到目标对象subject的观察者容器中
subject.addObserver(observerA);
subject.addObserver(observerA1);
subject.addObserver(observerA2);
// 改变subject对象的状态
subject.set(3000);
System.out.println(observerA.getMyState());
System.out.println(observerA1.getMyState());
System.out.println(observerA2.getMyState());
}
}
开发中常见的场景 :
聊天室程序的,服务器转发给所有客户端;网络游戏(多人联机对战)场景中,服务器将客户端的状态进行分发;邮件订阅;Servlet中,监听器的实现;Android中,广播机制;
JDK的AWT中事件处理模型,基于观察者模式的委派事件模型(Delegation Event Model)
事件源 ----- 目标对象
事件监听器 -----观察者
京东商城中,群发某商品打折信息
备忘录模式(memento) :
核心 : 就是保持某个对象内部状态的拷贝,这样以后就可以将该对象恢复到原先的状态.
结构 : 源发器类Originator;备忘录类Memento;负责人类CarTake.
备忘点较多时 :
将备忘录压栈
public class CareTaker {
private Memento memento;
private Stack<Memento> stack = new Stack<Memento>();
}
将多个备忘录对象,序列化和持久化;
开发中常见的应用场景 :
棋类游戏中的,悔棋;普通软件中的,撤销操作;数据库软件中的,事务管理中的,回滚操作;Photoshop软件中的,历史记录
例子 :
package com.example.demo.memento;
/**
* 源发器类
*/
public class Emp {
private String ename;
private int age;
private double salary;
public Emp(String ename, int age, double salary) {
this.ename = ename;
this.age = age;
this.salary = salary;
}
// 进行备忘操作,并返回备忘录对象
public EmpMemento memento() {
return new EmpMemento(this);
}
// 进行数据恢复,恢复成制定备忘录对象的值
public void recovery(EmpMemento mmt) {
this.ename = mmt.getEname();
this.age = mmt.getAge();
this.salary = mmt.getSalary();
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
package com.example.demo.memento;
/**
* 负责人类
* 负责管理备忘录对象
*/
public class CareTaker {
private EmpMemento empMemento;
public EmpMemento getEmpMemento() {
return empMemento;
}
public void setEmpMemento(EmpMemento empMemento) {
this.empMemento = empMemento;
}
}
package com.example.demo.memento;
/**
* 备忘录类
*/
public class EmpMemento {
private String ename;
private int age;
private double salary;
public EmpMemento(Emp e) {
this.ename = e.getEname();
this.age = e.getAge();
this.salary = e.getSalary();
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
package com.example.demo.memento;
public class Client {
public static void main(String[] args) {
CareTaker taker = new CareTaker();
Emp emp = new Emp("高琪", 18, 500);
System.out.println("第一打印创建对象 : " + emp.getEname() + "---" + emp.getAge() + "---" + emp.getSalary());
// 备忘一次
taker.setEmpMemento(emp.memento());
emp.setAge(38);
emp.setEname("王五");
emp.setSalary(800);
System.out.println("第二次打印创建对象 : " + emp.getEname() + "---" + emp.getAge() + "---" + emp.getSalary());
// 恢复到备忘录对象保存的状态
emp.recovery(taker.getEmpMemento());
System.out.println("第三次打印创建对象 : " + emp.getEname() + "---" + emp.getAge() + "---" + emp.getSalary());
}
}