行为型模式大全(Java讲解)


行为型模式关注系统中对象之间的相互交互,研究系统在运行时对象之间的相互通信和协作进一步明确对象的职责,共有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 of responsibility (常用)



定义:

  • 将能够处理同一类请求的对象连成一条链,所提交的请求沿着链传递,链上的对象逐个判断是否有能力处理该请求,如果能则处理,如果不能则传递给链上的下一个对象。

开发中常见的场景:

  • Java中,异常机制就是一种责任链模式。一个try可以对应多 个catch ,当第一个catch不匹配类型,则自动跳到第二个catch.
  • Javascript语言中, 事件的冒泡和捕获机制。Java语言中,事件的处理采用观察者模式。
  • Servlet开发中,过滤器的链式处理
  • Struts2中 ,拦截器的调用也是典型的责任链模式

模拟场景:
公司里面,请假条的审批过程:

  • 如果请假天数小于3天,主任审批
  • 如果请假天数大于等手3天,小于10天,经理审批
  • 如果大于等于10天,小于30天,总经理审批
  • 如果大于等于30天,提示拒绝

代码实现:

请假条类:

package 责任链模式;
/**
 * 封装请假的基本信息
 */
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 责任链模式;
/**
 * 抽象类:领导
 */
public abstract class Leader {
	protected String name;
	protected Leader nextLeader; //责任链的后继
	
	public Leader(String name) {
		super();
		this.name = name;
	}

	//设定责任链上的后继对象
	public void setNextLeader(Leader nextLeader) {
		this.nextLeader = nextLeader;
	}
	
	//处理请求的核心业务方法
	public abstract void handleRequest(LeaveRequest request);
}

主任类:

/**
 * 主任类
 */
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("主任:"+name+" 审批通过!");
		}else{
			if(this.nextLeader!=null){
				this.nextLeader.handleRequest(request);
			}
		}
	}
}

经理类:

/**
 * 经理类
 */
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("经理:"+name+" 审批通过!");
		}else{
			if(this.nextLeader!=null){
				this.nextLeader.handleRequest(request);
			}
		}
	}
}

总经理类:

/**
 * 总经理类
 */
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("总经理:"+name+" 审批通过!");
		}else{
			System.out.println("请假天数超过30天,拒绝审批!");
		}
	}
}

测试类:

/**
 * 测试类
 */
public class Client {
	public static void main(String[] args) {
		Leader a = new Director("张三");
		Leader b = new Manager("李四");
		Leader c = new GeneralManager("王五");
		
		//组织责任链对象的关系
		a.setNextLeader(b);
		a.setNextLeader(c);
		
		//开始请假操作
		LeaveRequest req1 = new LeaveRequest("TOM", 1, "回家探亲!");
		a.handleRequest(req1);
		LeaveRequest req2 = new LeaveRequest("TOM", 5, "回家探亲!");
		a.handleRequest(req2);
		LeaveRequest req3 = new LeaveRequest("TOM", 15, "回家探亲!");
		a.handleRequest(req3);
	}
}

测试结果:
员工:TOM请假,天数:1,理由:回家探亲!
主任:张三 审批通过!
员工:TOM请假,天数:5,理由:回家探亲!
总经理:王五 审批通过!
员工:TOM请假,天数:15,理由:回家探亲!
总经理:王五 审批通过!




迭代器模式(iterator)



场景:

  • 提供一种可以遍历聚合对象的方式。又称为:游标cursor模式
  • 聚合对象:存储数据
  • 迭代器:遍历数据

结构:

  • 聚合对象:存储数据
  • 迭代器:遍历数据

开发中常见的场景:

  • JDK内置的迭代器(List/Set)

代码实现:

接口定义:

package 迭代器模式;
/**
 * 自定义的迭代器接口
 */
public interface MyIterator {
	void first();   // 将游标指向第一个元素
	void next();	// 将游标指向下一个元素
	boolean hasNext();	// 判断是否存在下一个元素
	
	boolean isFirst();
	boolean isLast();
	
	Object getCurrentObje();	//获取当前游标指向的对象
}

用内部类实现迭代器:

package 迭代器模式;

import java.util.ArrayList;
import java.util.List;

public class ConcreteMyAggregate {
	private List<Object> list = new ArrayList<Object>();


	
	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 getCurrentObje() {
			return list.get(cursor);
		}
	}
}

测试类:

public class client {
	public static void main(String[] args) {
		ConcreteMyAggregate cma = new ConcreteMyAggregate();
		cma.addObject("aa");
		cma.addObject("bb");
		cma.addObject("cc");
		
		MyIterator iter = cma.createIterator();
		while(iter.hasNext()){
			System.out.println(iter.getCurrentObje());
			iter.next();
		}
	}
}

测试结果:
aa
bb
cc




中介者模式(Mediator)


核心:

  • 如果一个系统中对象之间的联系呈现为网状结构,对象之间存在大量多对多关系,将导致关系及其复杂,这些对象称为“同事对象”
  • 我们可以引入一个中介者对象,使各个同事对象只跟中介者对象打交道,将复杂的网络结构化解为如下的星形结构。
    在这里插入图片描述

结构图:
在这里插入图片描述
中介者模式的本质:

  • 解耦多个同事对象之间的交互关系。每个对象都持有中介者对象的引用,只跟中介者对象打交道。我们通过中介者对象统一管理这些交互关系

开发中常见的场景:

  • MVC模式(其中的C ,控制器就是一个中介者对象。M和V都和他打交道)

  • 窗口游戏程序,窗口软件开发中窗口对象也是一个中介者对象

  • 图形界面开发GUI中,多个组件之间的交互,可以通过引入一个中介者对象来解决,可以是整体的窗口对象或者DOM对象

  • Java.lang.reflect.Method#invoke()

下面以总经理和各部门的关系进行举例:

代码实现:

部门类的接口:

//部门类的接口
public interface Department {
	void selfAction();  //做本部门的事情
	void outAction();   //向总经理发出申请
}

中介者接口:

//中介者接口
public interface Mediator {
	void register(String dname, Department d);  //注册部门
	void command(String dname);  //发布命令
}

研发部:

//研发部
public class Development implements Department {

	private Mediator m;  //持有中介者(总经理)的引用
	
	public Development(Mediator m) {
		super();
		this.m = m;
		m.register("development", this); //将当前对象注册到中介者那
	}

	@Override
	public void selfAction() {
		System.out.println("汇报工作,申请资金");
		m.command("Finacial"); //由总经理和财务部沟通
	}

	@Override
	public void outAction() {
		System.out.println("专心科研,开发项目");
	}	
}

财务部:

//财务部
public class Finacial implements Department {

	private Mediator m;  //持有中介者(总经理)的引用
	
	public Finacial(Mediator m) {
		super();
		this.m = m;
		m.register("Finacial", this); //将当前对象注册到中介者那
	}

	@Override
	public void selfAction() {
		System.out.println("汇报资金情况");
	}

	@Override
	public void outAction() {
		System.out.println("数钱");
	}
	
}
//市场部
public class Market implements Department {

	private Mediator m;  //持有中介者(总经理)的引用
	
	public Market(Mediator m) {
		super();
		this.m = m;
		m.register("Market", this); //将当前对象注册到中介者那
	}

	@Override
	public void selfAction() {
		System.out.println("汇报市场调查情况");
	}

	@Override
	public void outAction() {
		System.out.println("做市场调查,接项目,需要资金");
		m.command("Finacial"); //由总经理和财务部沟通
	}	
}

总经理类(中介者):

import java.util.HashMap;
import java.util.Map;

//总经理类(中介者)
public class President implements Mediator{
	private Map<String, Department> map = new HashMap<String, Department>();

	@Override
	public void register(String dname, Department d) {
		map.put(dname, d);
	}

	@Override
	public void command(String dname) {
		map.get(dname).selfAction();
	}
}

测试类:

//测试类
public class client {
	public static void main(String[] args) {
		Mediator m = new President();
		
		Market market = new Market(m);
		Development devp = new Development(m);
		Finacial f = new Finacial(m);
		
		market.selfAction();
		market.outAction();
	}
}

UML图:
在这里插入图片描述




命令模式(command)(不常用)


介绍:

  • 命令模式:将-一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。也称之为:动作Action模式、事务transaction模式

结构:

  • Command抽象命令类
  • ConcreteCommand具体命令类
  • Invoker调用者/请求者
    ●请求的发送者,它通过命令对象来执行请求。一一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联。在程序运行时,将调用命令对象的execute0 ,间接调用接收者的相关操作。
  • Receiver接收者
    ●接收者执行与请求相关的操作,具体实现对请求的业务处理。
    ●未抽象前,实际执行操作内容的对象。
  • Client客户类
    ●在客户类中需要创建调用者对象、具体命令类对象,在创建具体命令对象时指定对应的接收者。发送者和接收者之间没有直接关系,都通过命令对象间接调用。

UML图:
在这里插入图片描述

开发中常见的场景:

  • Struts2中 , action的整个调用过程中就有命令模式。
  • 数据库事务机制的底层实现
  • 命令的撤销和恢复



解释器模式(interpreter)(不常用)


介绍:

  • 是一种不常用的设计模式
  • 用于描述如何构成一 个简单的语言解释器,主要用于使用面向对象语言开发的编译器和解释器设计。
  • 当我们需要开发一种新的语言时,可以考虑使用解释器模式。
  • 尽量不要使用解释器模式,后期维护会有很大麻烦。在项目中,可以使用Jruby , Groovy、java的js引擎来替代解释器的作用,弥补java语言的不足。

应用的场景:

  • EL表达式式的处理
  • 正则表达式解释器
  • SQL语法的解释器
  • 数学表达式解析器



访问者模式 (visitor)(不常用)


模式动机:

  • 对于存储在一个集合中的对象,他们可能具有不同的类型(即使有一个公共的接口) ,对于该集合中的对象,可以接受一类称为访问者的对象来访问 ,不同的访问者其访问方式也有所不同。

定义:

  • 表示一个作用于某对象结构中的各元素的操作,它使我们可以在不改变个元素的类的前提下定义作用于这些元素的新操作。

开发中的场景(应用范围非常窄,了 解即可) :

  • XML文档解析器设计
  • 编译器的设计
  • 复杂集合对象的处理



策略模式 (strategy)(常用)


介绍:

  • 策略模式对应于解决某一个问题的一 个算法族,允许用户从该算法族中任选一个算法解决某一问题 ,同时可以方便的更换算法或者增加新的算法。并且由客户端决定调用哪个算法。

场景:

  • 某个市场人员接到单后的报价策略(CRM系统中常见问题)。报价策略很复杂,可以简单作如下分类:
    • 普通客户小批量报价
    • 普通客户大批量报价
    • 老客户小批量报价
    • 老客户大批量报价
  • 具体选用哪个报价策略,这需要根据实际情况来确定。这时候,我们采用策略模式即可。

对于上面这个场景,不采用策略模式的情况下,我们可以使用条件语句(if else)判断处理。但是,假如,类型特别多,算法比较复杂时,整个条件控制代码会变得很长,难于维护。

开发中常见的场景:

  • JAVASE中GUI编程中,布局管理
  • Spring框架中, Resource接口,资源访问策略
  • javax.servlet.http.HttpServlet#service()

实现报价场景的代码:

//策略接口
public interface Strategy {
	public double getPrice(double standardPrice);
}

新客户小批量策略:

//新客户小批量策略
public class NewCustomerFewStrategy implements Strategy{

	@Override
	public double getPrice(double standardPrice) {
		System.out.println("不打折,原价");
		return standardPrice;
	}
}

新客户大批量策略:

//新客户大批量策略
public class NewCustomerManyStrategy implements Strategy{

	@Override
	public double getPrice(double standardPrice) {
		System.out.println("九折");
		return standardPrice*0.9;
	}
}

老客户小批量策略:

//老客户小批量策略
public class OldCustomerFewStrategy implements Strategy{

	@Override
	public double getPrice(double standardPrice) {
		System.out.println("八五折");
		return standardPrice*0.85;
	}
}

老客户大批量策略:

//老客户大批量策略
public class OldCustomerManyStrategy implements Strategy{

	@Override
	public double getPrice(double standardPrice) {
		System.out.println("八折");
		return standardPrice*0.8;
	}
}

实现交换的类:

/**
 * 负责和具体的策略类交互
 * 这样的话,具体的算法和直接的客户端调用分离了,使得算法可以独立于客户端独立的变化
 */
public class Context {
	private Strategy strategy;  //当前采用的算法对象

	//可以通过构造器注入
	public Context(Strategy strategy) {
		super();
		this.strategy = strategy;
	}

	//通过set方法注入
	public void setStrategy(Strategy strategy) {
		this.strategy = strategy;
	}
	
	public void pringPrice(double s){
		System.out.println("您的报价为:"+strategy.getPrice(s));
	}
}

测试类:

//测试类
public class Client {
	public static void main(String[] args) {
		Strategy s1 = new OldCustomerManyStrategy();//老客户
		Context ctx = new Context(s1);
		
		ctx.pringPrice(100);
	}
}

测试结果:
八折
您的报价为:80.0




模板方法模式 template method (常用)


模板方法模式介绍:

  • 模板方法模式是编程中经常用得到模式。它定义了一个操作中的算法骨架,将某些步骤延迟到子类中实现。这样,新的子类可以在不改变一个算法结构的前提下重新定义该算法的某些特定步骤。

核心:

  • 处理某个流程的代码已经都具备,但是其中某个节点的代码暂时不能确定。因此,我们采用工厂方法模式,将这个节点的代码实现转移给子类完成。即:处理步骤父类中定义好,具体实现延迟到子类中定义

案例代码:
在这里插入图片描述

什么时候用到模板方法模式:

  • 实现一个算法时,整体步骤很固定。但是,某些部分易变。易变部分可以抽象成出来,供子类实现。

开发中常见的场景:

  • 非常频繁。各个框架、类库中都有他的影子。比如常见的有:
    • 数据库访问的封装
    • Junit单元测试
    • servlet中关 于doGet/doPost方法调用
    • Hibernate中模板程序
    • spring中JDBCTemplate、 HibernateTemplate等。

代码实现:

public abstract class BankTempLateMethod {
	//具体方法
	public void takeNumber(){
		System.out.println("区号排队");
	}
	
	public abstract void transact();//办理具体的业务
	
	public void evaluate(){
		System.out.println("反馈评分");
	}
	
	//因为所有业务的处理步骤是相同的,所以final修饰,之后的子类都不能修改
	public final void process(){  //模板方法
		this.takeNumber();
		this.transact();
		this.evaluate();
	}
}

测试类:

public class Client {
	public static void main(String[] args) {
		BankTempLateMethod btm = new DrawMoney();
		btm.process();
		
		System.out.println("-----------------");  //分隔符
		
		//采用匿名内部类实现(和使用匿名内部类重写run()方法建立线程类似)
		BankTempLateMethod btm2 = new BankTempLateMethod(){

			@Override
			public void transact() {
				System.out.println("我要贷款");
			}
		};
		btm.process();
	}
}

class DrawMoney extends BankTempLateMethod {
	@Override
	public void transact() {
		System.out.println("我要取款");
	}
}

测试结果:

区号排队
我要取款
反馈评分
-----------------
区号排队
我要取款
反馈评分



状态模式 (state)


场景:
酒店系统中,房间的状态变化:

  • 已预订
  • 已入住
  • 空闲

在这里插入图片描述

当遇到这种需要频繁修改状态时,可以考虑状态模式。

核心:

  • 用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题

结构:

  • Context环境类
    环境类中维护一个State对象 ,他是定义了当前的状态。
  • State抽象状态类
  • ConcreteState具体状态类
    每一个类封装了-个状态对应的行为

开发中常见的场景:

  • 银行系统中账号状态的管理
  • OA系统中公文状态的管理
  • 酒店系统中,房间状态的管理
  • 线程对象各状态之间的切换

代码实现:

//状态接口
public interface State {
	void handle();
}

空闲状态:

/**
 * 空闲状态
 */
public class FreeState implements State{

	@Override
	public void handle() {
		System.out.println("空闲状态,可以入住");
	}
}

已预订状态:

/**
 * 已预订状态
 */
public class BookedState implements State{

	@Override
	public void handle() {
		System.out.println("已预订状态,不可入住");
	}
}

已入住状态:

/**
 * 已入住状态
 */
public class CheckedInState implements State{

	@Override
	public void handle() {
		System.out.println("房间已入住,请勿打扰");
	}
}

房间类:

/**
 * 房间类
 */
public class Context {
	//如果是银行系统,这个Context类就是账号,根据金额的不同,切换不同的状态
	
	private State state;
	
	public void setState(State s){
		System.out.println("修改状态!");
		state = s;
		state.handle();
	}
}

测试类:

/**
 * 测试类
 */
public class Client {
	public static void main(String[] args) {
		Context ctx = new Context();
		
		ctx.setState(new FreeState());
		ctx.setState(new BookedState());
	}
}

测试结果:

修改状态!
空闲状态,可以入住
修改状态!
已预订状态,不可入住

UML图:
在这里插入图片描述




观察者模式 (observer)(常用)


场景:

  • 聊天室程序的创建。服务器创建好后, A,B,C3三个客户端连上来公开聊.天。A向服务器发送数据,服务器端聊天数据改变。我们希望将这些聊天数据分别发给其他在线的客户。也就是说,每个客户端需要更新服务器端得数据。
  • 网站上,很多人订阅了”java主题”的新闻。当有这个主题新闻时,就会将这些新闻发给所有订阅的人。
  • 大家一起玩CS游戏时,服务器需要将每个人的方位变化发给所有的客户。

  上面这些场景,我们都可以使用观察者模式来处理。我们可以把多个订阅者、客户称之为观察者;需要同步给多个订阅者的数据封装到对象中,称之为目标

核心:

  • 观察者模式主要用于1 : N的通知。当一个对象(目标对象Subject或Objservable)的状态变化时,他需要及时告知一系列对象(观察者对象,Observer) ,令他们做出响应
  • 通知观察者的方式:
    • 推:每次都会把通知以广播方式发送给所有观察者,所有观察者只能被动接收。
    • 拉:观察者只要直到有情况即可。至于什么时候获取内容,获取什么内容,都可以自己决定。

开发中常见的场景:

  • 聊天室程序的,服务器转发给所有客户端
  • 网络游戏(多 人联机对战)场景中,服务器将客户端的状态进行分发
  • 邮件订阅
  • Servlet中 ,监听器的实现
  • Android中 ,广播机制
  • JDK的AWT中事件处理模型,基于观察者模式的委派事件模型(Delegation EventModel)
    事件-----------目标对象
    事件监听--------观察者
  • 京东商城中,群发某商品打折信息

代码实现:

/**
 * 观察者接口
 */
public interface Observer {
	void update(Subject subject);
}
/**
 * 目标类(相当于广播)
 */
public class Subject {
	protected List<Observer>  list = new ArrayList<Observer>();
	
	//注册观察者
	public void registerObserver(Observer obs){
		list.add(obs);
	}
	
	//删除观察者
	public void removeObserver(Observer obs){
		list.remove(obs);
	}
	
	//通知所有的观察者更新状态
	public void notifyAllObservers(){
		for (Observer objs : list) {
			objs.update(this);
		}
	}
}

目标对象:

public class ConcreteSubject extends Subject{
	private int state;
	
	public int getState(){
		return state;
	}
	
	public void setState(int state){
		this.state = state;
		//主题对象(目标对象)值发生了变化,通知所有观察者
		this.notifyAllObservers();
	}
}
/**
 * 观察者
 */
public class ObserverA implements Observer{

	private int myState;  //需要跟目标对象的state值保持一致
	
	public int getMyState() {
		return myState;
	}

	public void setMyState(int myState) {
		this.myState = myState;
	}

	@Override
	public void update(Subject subject) {
		myState = ((ConcreteSubject)subject).getState();
	}
}

测试类:

//测试类
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());
	}
}

测试结果:
3000
3000
3000

UML图:
在这里插入图片描述

  其实,JAVASE提供了java.util.Observablejava.util.Observer来实现观察者模式。不需要我们再创建。
  下面用JDK提供的java.util.Observablejava.util.Observer来实现观察者模式:

目标类:

import java.util.Observable;

public class ConcreteSubject extends Observable{
	
	private int state;
	
	public void set(int s){
		state = s;    //目标对象的状态发生了改变
		
		setChanged();  //表示目标对象已经做了更改
		notifyObservers(state);  //通知所有的观察者
	}
	
	public int getState() {
		return state;
	}

	public void setState(int state) {
		this.state = state;
	}
	
}

观察者类:

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;
	}
	
}

测试类:

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.addObserver(obs1);
		subject.addObserver(obs2);
		subject.addObserver(obs3);
		
		//改变subject对象的状态
		subject.set(300);
		
		//观察者的状态发生了变化
		System.out.println(obs1.getMyState());
		System.out.println(obs2.getMyState());
		System.out.println(obs3.getMyState());
	}
}

测试结果:
300
300
300




备忘录模式(memento)


场景:

  • 录入大批人员资料。正在录入当前人资料时,发现上-一个人录错了,此时需要恢复上一个人的资料,再进行修改。
  • Word文档编辑时,忽然电脑死机或断电,再打开时,可以看到word提示你恢复到以前的文档
  • 管理系统中,公文撤回功能。公文发送出去后,想撤回来。

核心:

  • 就是保存某个对象内部状态的拷贝,这样以后就可以将该对象恢复到原先的状态。

结构:

  • 源发器类Originator
  • 备忘录类Memento
  • 负责人类CareTake

开发中常见的应用场景:

  • 棋类游戏中的,悔棋
  • 普通软件中的,撤销操作
  • 数据库软件中的, 事务管理中的,回滚操作
  • Rhotoshop软件中的,历史记录

代码实现:

源发器类:

package 备忘录模式;
/**
 * 源发器类
 */
public class Emp {
	private String ename;
	private int age;
	private double salary;
	
	//进行数据恢复,并返回备忘录对象
	public EmpMemento memento(){
		return new EmpMemento(this);
	}
	
	//进行数据恢复,恢复成指定备忘录对象的值
	public void recover(EmpMemento mmt){
		this.ename = mmt.getEname();
		this.age = mmt.getAge();
		this.salary = mmt.getSalary();
	}
	
	public Emp(String ename, int age, double salary) {
		super();
		this.ename = ename;
		this.age = age;
		this.salary = salary;
	}
	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 备忘录模式;
/**
 * 备忘录类
 */
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;
	}
}
/**
 * 负责人类
 * 负责管理备忘录对象
 */
public class CareTaker {
	private EmpMemento memento;

	//备忘录比较多时,可以使用容器进行存储,或者是用栈进行存储
//	private List<EmpMemento> list = new ArrayList<EmpMemento>();
	
	public EmpMemento getMemento() {
		return memento;
	}

	public void setMemento(EmpMemento memento) {
		this.memento = memento;
	}
}

测试类:

public class Client {
	public static void main(String[] args) {
		CareTaker taker = new CareTaker();
		
		Emp emp = new Emp("王一", 18, 900);
		System.out.println("第一次打印对象:"+emp.getEname()+"---"+emp.getAge()+"---"+emp.getSalary());
		
		taker.setMemento(emp.memento());  //备忘一次
		
		emp.setAge(38);
		emp.setEname("王二");
		emp.setSalary(9000);
		System.out.println("第二次打印对象:"+emp.getEname()+"---"+emp.getAge()+"---"+emp.getSalary());
		
		emp.recover(taker.getMemento());  //恢复到备忘录对象保存的状态
		
		System.out.println("第三次打印对象:"+emp.getEname()+"---"+emp.getAge()+"---"+emp.getSalary());
	}
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逍遥自在”

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值