设计模式中的第三类是行为型模式,共11种,分别为:
策略、模板方法、观察者、责任链、 迭代子、备忘录、状态、命令、解释器、访问者、调停者。
本篇介绍其中的 迭代子、备忘录、状态、命令 四种。
Iterator
迭代子模式
1 迭代子模式 又叫游标模式,是对象的行为模式。迭代子模式可以顺序地访问一个聚集中的元素和不必保留聚集的内部表象。
2 java JDK 集合类库中大量使用到了迭代子模式。如Iterator、ListIterator、Enumeration 等。
3 迭代子模式中涉及到的几个角色
抽象迭代子(Iterator): 此角色定义出遍历元素所需的接口。
具体迭代子(ConcreteIterator): 此角色实现Iterator接口,并保持迭代过程中的游标位置
聚集角色(Aggregate):此抽象角色给出创建迭代子对象的接口
具体聚集(ConcreteAggregate):实现创建迭代子对象的接口
客户端(client): 持有对聚集及其迭代子对象的引用,调用迭代子对象的迭代接口,也有可能通过迭代子操作聚集元素的添加和删除。
java示例代码
Aggregate 抽象聚集/集合 接口
package com.jelly.mypattern.iterator;
/**
* 抽象聚集 定义接口
* @author jelly
*
*/
public interface Aggregate {
public Iterator iterator();
}
具体聚集类 ConcreteAggregate
package com.jelly.mypattern.iterator;
/**
* 具体聚集
* @author jelly
*
*/
public class ConcreteAggregate implements Aggregate{
private Object[] objs=new Object[]{"aaa","bbb","ccc","ddd"};
@Override
public Iterator iterator() {
return new ConcreteIterator();
}
/**
*
* 在聚集对象的内部定义个 迭代子对象(也叫内禀迭代子)
* 实现迭代接口,提供给客户端一个迭代对象。
* @author jelly
*
*/
public class ConcreteIterator implements Iterator{
private int currentIndex=0;
//移动游标 到第一个元素
@Override
public void first() {
currentIndex=0;
}
//移动游标到下一个元素
@Override
public void next() {
if(currentIndex<objs.length){
currentIndex++;
}
}
//是否到了最后一个元素
@Override
public boolean isDone() {
return (currentIndex==objs.length);
}
//获取当前元素
@Override
public Object currentItem() {
return objs[currentIndex];
}
}
}
迭代接口 Iterator
package com.jelly.mypattern.iterator;
/**
* 迭代接口
* @author jelly
*
*/
public interface Iterator {
//迭代方法 移动游标到第一个元素
public void first();
//迭代方法 移动游标到下一个元素
public void next();
//迭代方法 判断是否是最后一个元素
public boolean isDone();
//迭代方法 获取当前迭代到的元素
public Object currentItem();
}
测试代码
package com.jelly.mypattern.iterator;
/**
* 客户端测试代码
* @author jelly
*
*/
public class IteratorTest {
public static void main(String[] args) {
Aggregate aggregate=new ConcreteAggregate();//得到聚集对象
Iterator it= aggregate.iterator();//调用聚集对象的iterator()方法 返回内部的一个迭代子对象。
//使用迭代子对象进行迭代 操作
while(!it.isDone()){
System.out.println(it.currentItem());
it.next();
}
}
}
控制台输出:
aaa
bbb
ccc
ddd
Memento
备忘录模式
1 备忘录模式是对象的行为模式,又叫快照(snapShot)模式、备份模式。备忘录是一个存储另一个对象内部状态的快照对象。其用意是在不破坏封装的条件下,将一个对象的状态捕捉住,并外部化存储起来,
这样可以在将来的合适时候将这个对象的状态进行还原。
2 备忘录模式中的角色
发起人角色(Originator): 创建含有当前内部状态的备忘录对象,使用备忘录对象存储其内部状态
负责人角色(Caretaker):负责保存备忘录对象,不检查备忘录对象中的内容。
备忘录角色(Memento):将发起人对象的内部状态存储起来,保护其内容不被发起人对象之外的任何对象所获取。
3 备忘录模式中的黑箱实现。
将Memento 设置为Originator类的内部类,从而将Memento对象封装在Originator里面。在外部提供一个标示接口MementoIF给Caretaker以及其他对象。这样,Originator类看到的
是Memento的所有接口,而Caretaker以及其他对象看到的仅仅是标识接口MementoIF,巧妙地实现了双重接口(对发起人和负责人)。
4 备忘录的典型应用例子:
文本编辑器中按 ctrl+z 撤销功能。
java示例代码:
原对象,备忘录发起人
package com.jelly.mypattern.memento;
/**
* 备忘录发起者
* @author jelly
*
*/
public class Originator {
private String state;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public Originator() {
}
//创建备忘录
public MementoIF createMemento(){
System.out.println("备份我的状态:"+this.state);
return new Memento(this.state);
}
//恢复备忘录
public void restoreMemento(MementoIF mementoIF){
Memento memento=(Memento)mementoIF;
this.setState(memento.getSavedState());
System.out.println("恢复我的状态:"+this.getState());
}
/**
* 内部成员 内部类 备忘录
* @author jelly
*
*/
public class Memento implements MementoIF{
private String savedState;
public String getSavedState() {
return savedState;
}
public void setSavedState(String savedState) {
this.savedState = savedState;
}
public Memento(){
}
public Memento(String savedState){
this.savedState=savedState;
}
}
}
备忘录标识接口
package com.jelly.mypattern.memento;
public interface MementoIF {
}
备忘录负责人
package com.jelly.mypattern.memento;
import java.util.Stack;
/**
* 备忘录负责人
* @author jelly
*
*/
public class CareTaker {
//备忘录栈
private Stack<MementoIF> memStack=new Stack<MementoIF>();
//每获取一个备忘录 出栈一次
public MementoIF getMemento(){
return memStack.pop();
}
//每存入一个备忘录 入栈一次
public void saveMemento(MementoIF memento){
memStack.push(memento);
}
}
测试代码:
package com.jelly.mypattern.memento;
/**
* 备忘录模式 测试代码
* @author jelly
*
*/
public class MementoTest {
public static void main(String[] args) {
Originator originator=new Originator();
CareTaker careTaker=new CareTaker();
//原始对象 状态变为了stateA
originator.setState("A");
System.out.println("我的状态变为了A");
//原对象 备份了自己状态(建立了一个备忘录),将备忘录交给careTaker去保存
careTaker.saveMemento(originator.createMemento());//创建备份,保存状态到careTaker的备忘录栈中
originator.setState("B");
System.out.println("我的状态变为了B");
careTaker.saveMemento(originator.createMemento());//创建备份,保存状态到careTaker的备忘录栈中
originator.setState("C");
System.out.println("我的状态变为了C");
careTaker.saveMemento(originator.createMemento());//创建备份,保存状态到careTaker的备忘录栈中
originator.setState("D");
System.out.println("我的状态变为了D");
originator.restoreMemento(careTaker.getMemento());//还原一次 状态为C
System.out.println("我的状态还原为了:"+originator.getState());
originator.restoreMemento(careTaker.getMemento());//再还原一次 状态为B
System.out.println("我的状态还原为了:"+originator.getState());
originator.restoreMemento(careTaker.getMemento());//再还原一次 状态为A
System.out.println("我的状态还原为了:"+originator.getState());
}
}
控制台输出:
我的状态变为了A
备份我的状态:A
我的状态变为了B
备份我的状态:B
我的状态变为了C
备份我的状态:C
我的状态变为了D
恢复我的状态:C
我的状态还原为了:C
恢复我的状态:B
我的状态还原为了:B
恢复我的状态:A
我的状态还原为了:A
State
状态模式
1 状态模式又叫状态对象模式,是对象的行为模式。状态模式允许对象的内部状态发生改变是改变其行为,看上去象改变了类一样。
2 状态模式中涉及的角色
状态角色(State): 定义一个接口,用以封装环境对象的一个特定状态所对应的行为。
具体状态角色(ConcreteState):每一个具体状态类都实现了环境的一个状态所对应的行为。
环境角色(Context):定义客户端所感兴趣的接口,并保留一个具体状态类的实例。这个具体状态类的实例给出此环境对象的现有状态。
3 一个典型的例子 TcpConnection。
Tcp连接中可能的状态有这么几种, Established(已建立),Listening(监听中),Closed(已关闭)
当TcpConnection对象其他对象的请求时,会根据其状态的不同而做出不同的应答。
比如,TcpConnction;回应客户端的开启请求取决于TcpConnection是Establised还是Closed
java示例代码:
TcpConnect 连接对象 环境对象
package com.jelly.mypattern.state;
/**
* tcp 连接对象 环境对象
* @author jelly
*
*/
public class TcpConnection {
public static final TcpState TCPSTATE_ESTABLISHED=new TcpEstablished();//具体状态对象
public static final TcpState TCPSTATE_LISTEN=new TcpListen();//具体状态对象
public static final TcpState TCPSTATE_CLOSED=new TcpClosed();//具体状态对象
private TcpState tcpState;//状态 接口
public TcpState getTcpState() {
return tcpState;
}
public void setTcpState(TcpState tcpState) {
this.tcpState = tcpState;
}
public void open(){
this.tcpState.open();
}
public void closed(){
this.tcpState.close();
}
public void ack(){
this.tcpState.ack();
}
}
tcp 连接状态 接口
package com.jelly.mypattern.state;
/**
* tcp 状态接口
* @author jelly
*
*/
public interface TcpState {
public void open();
public void close();
public void ack();
}
下面是3个具体的状态类 TcpEstablished 状态
package com.jelly.mypattern.state;
/**
* tcp状态 连接已建立
* @author jelly
*
*/
public class TcpEstablished implements TcpState{
@Override
public void open() {
System.out.println("tcp连接已建立,不可重复建立");
}
@Override
public void close() {
System.out.println("tcp连接成功关闭");
}
@Override
public void ack() {
System.out.println("tcp连接已建立,无须ack操作");
}
}
TcpListen 状态
package com.jelly.mypattern.state;
/**
* tcp状态 监听中
* @author jelly
*
*/
public class TcpListen implements TcpState{
@Override
public void open() {
System.out.println("tcp连接建立成功");
}
@Override
public void close() {
System.out.println("tcp已挂监听");
}
@Override
public void ack() {
System.out.println("tcp ack确认成功");
}
}
TcpClosed 状态
package com.jelly.mypattern.state;
/**
* tcp状态 连接已关闭
* @author jelly
*
*/
public class TcpClosed implements TcpState{
@Override
public void open() {
throw new IllegalAccessError("非法的访问,连接已关闭");
}
@Override
public void close() {
System.out.println("tcp连接已关闭");
}
@Override
public void ack() {
throw new IllegalAccessError("非法的访问,连接已关闭");
}
}
测试代码:
package com.jelly.mypattern.state;
/**
* 状态模式测试 类
* @author jelly
*
*/
public class StateTest {
public static void main(String[] args) {
TcpConnection conn=new TcpConnection();
conn.setTcpState(TcpConnection.TCPSTATE_LISTEN);
conn.open();
conn.setTcpState(TcpConnection.TCPSTATE_ESTABLISHED);
conn.closed();
conn.setTcpState(TcpConnection.TCPSTATE_CLOSED);
conn.open();//由于tcp连接已关闭,调用open()方法将抛出异常 。
}
}
控制台输出:
tcp连接建立成功
tcp连接成功关闭
Exception in thread "main" java.lang.IllegalAccessError: 非法的访问,连接已关闭
at com.jelly.mypattern.state.TcpClosed.open(TcpClosed.java:11)
at com.jelly.mypattern.state.TcpConnection.open(TcpConnection.java:22)
at com.jelly.mypattern.state.StateTest.main(StateTest.java:16)
Command
命令模式
1 命令模式属于对象的行为模式,有称为行动描述或交易模式。命令模式把一个请求或操作封装到一个对象中。命令模式允许系统使用不用的请求把客户端参数化,对请求排队或记录请求日志,可以提供名的撤销和恢复功能。
2 命令模式中的角色
客户角色(Client):创建一个具体命令对象并确定其接受者
命令角色(Command): 声明一个具体命令所需要实现的接口。
具体命令角色(ConcreteCommand):定义一个接收者和行为之间的弱耦合。负责调用接收者的响应操作。
命令请求者(Invoker):负责调用命令对象执行请求,相关的方法叫做行动方法。
命令接收者(Receiver):负责具体实施和执行一个请求。实施和执行请求的方法叫做行动方法。
java示例代码:
命令发起者、调用者Invoker
package com.jelly.mypattern.command;
/**
* 命令发起人
* @author jelly
*
*/
public class Invoker {
private Command command;
public Invoker(Command command){
this.command=command;
}
public void action(){
command.execute();
}
}
命令接口Command
package com.jelly.mypattern.command;
/**
* 抽象命令接口
* @author jelly
*
*/
public interface Command {
public void execute();
}
具体命令ConcreteCommand
package com.jelly.mypattern.command;
/**
* 具体命令
* @author jelly
*
*/
public class ConcreteCommand implements Command{
//命令接收者
private Receiver receiver;
public ConcreteCommand(Receiver receiver) {
this.receiver=receiver;
}
@Override
public void execute() {
receiver.action();//接收者执行命令
}
}
命令接收者、执行者 Receiverpackage com.jelly.mypattern.command;
/**
* 命令接收者 执行者
* @author jelly
*
*/
public class Receiver {
public Receiver() {
super();
}
public void action(){
System.out.println("命令 已被执行。。。");
}
}
测试代码:
package com.jelly.mypattern.command;
/**
* 命令模式 测试代码
* @author jelly
*
*/
public class CommandTest {
public static void main(String[] args) {
Receiver receiver=new Receiver();
//命令对象, 指定命令的接收者
Command command =new ConcreteCommand(receiver);
//调用者发出一道命令,这道命令由一个命令对象封装表示
Invoker invoker=new Invoker(command);
invoker.action();
}
}
控制台输出:
命令 已被执行。。。
。。。。。。