本文主要介绍Java面向对象23种设计模式中行为型模式中的部分设计模式,上接Java面向对象设计模式学习(六)。
八、迭代器模式(了解)
迭代器模式面向的问题是:通常,集合的创建与遍历都在同一个类中,当遍历方法更换时就必须修改程序源代码,违背了 “开闭原则”。迭代器模式是指在客户访问类与聚合类之间插入一个迭代器,即提供一个对象来顺序访问集合对象中的一系列数据,而不暴露集合对象的内部表示。
迭代器模式主要角色如下:
- 抽象聚合(Aggregate)角色:定义存储、添加、删除聚合对象以及创建迭代器对象的接口。
- 具体聚合(ConcreteAggregate)角色:实现抽象聚合类,返回一个具体迭代器的实例。
- 抽象迭代器(Iterator)角色:定义访问和遍历聚合元素的接口,通常包含 hasNext()、first()、next() 等方法。
- 具体迭代器(Concretelterator)角色:实现抽象迭代器接口中所定义的方法,完成对聚合对象的遍历,记录遍历的当前位置。
以上结构图对应的实例代码如下:
import com.sun.corba.se.spi.ior.ObjectKey;
import java.util.ArrayList;
import java.util.List;
//抽象集合
interface Aggregate{
public void add(Object obj);
public void remove(Object obj);
public Iterator getIterator();
}
//具体集合
class ConcreteAggregate implements Aggregate{
private List<Object> list=new ArrayList<Object>();
@Override
public void add(Object obj) {
list.add(obj);
}
@Override
public void remove(Object obj) {
list.remove(obj);
}
@Override
public Iterator getIterator() {
return (new ConcreteIterator(list));
}
}
//抽象迭代器
interface Iterator{
Object first();
Object next();
boolean hasNext();
}
//具体迭代器
class ConcreteIterator implements Iterator{
private List<Object> list=null;
private int index=-1;
public ConcreteIterator(List<Object> list){
this.list=list;
}
@Override
public Object first() {
index=0;
Object obj=list.get(index);
return obj;
}
@Override
public Object next() {
Object obj=null;
if(this.hasNext()){
obj=list.get(++index);
}
return obj;
}
@Override
public boolean hasNext() {
if(index<list.size()-1){
return true;
}else {
return false;
}
}
}
public class IteratorPattern{
public static void main(String[] args) {
Aggregate aggregate=new ConcreteAggregate();
aggregate.add("小米手机");
aggregate.add("华为手机");
aggregate.add("苹果手机");
System.out.println("集合中的元素有:");
Iterator iterator=aggregate.getIterator();
while (iterator.hasNext()){
Object obj=iterator.next();
System.out.println(obj.toString()+"\t");
}
Object obj=iterator.first();
System.out.println("\n第一个元素为:"+obj.toString());
}
}
程序输出结果如下:
集合中的元素有:
小米手机
华为手机
苹果手机
第一个元素为:小米手机
九、访问者模式
访问者模式面向的问题是:有些集合对象中存在多种不同的元素,且每种元素也存在多种不同的访问者和处理方式。例如,医院医生开的处方单中包含多种药,査看它的划价员和药房工作人员对它的处理方式不同;一部电影,不同观众 评价也不相同。
访问者模式将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式。它将对数据的操作与数据结构进行分离,是行为类模式中最复杂的一种模式。
访问者(Visitor)模式实现的关键是如何将作用于元素的操作分离出来封装成独立的类 。
访问者模式的主要角色如下:
- 抽象访问者(Visitor)角色:定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作 visit() ,该操作中的参数类型标识了被访问的具体元素。
- 具体访问者(ConcreteVisitor)角色:实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么。
- 抽象元素(Element)角色:声明一个包含接受操作 accept() 的接口,被接受的访问者对象作为 accept() 方法的参数。
- 具体元素(ConcreteElement)角色:实现抽象元素角色提供的 accept() 操作,其方法体通常都是 visitor.visit(this) ,另外具体元素中可能还包含本身业务逻辑的相关操作。
- 对象结构(Object Structure)角色:是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由 List、Set、Map 等聚合类实现。
以上结构图对应的实例代码如下:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
//抽象访问者
interface Visitor{
void visit(ConcreteElementA element);
void visit(ConcreteElementB element);
}
//具体访问者A类
class ConcreteVisitorA implements Visitor{
@Override
public void visit(ConcreteElementA element) {
System.out.println("具体访问者A访问-->"+element.operationA());
}
@Override
public void visit(ConcreteElementB element) {
System.out.println("具体访问者A访问-->"+element.operationB());
}
}
//具体访问者B类
class ConcreteVisitorB implements Visitor
{
public void visit(ConcreteElementA element)
{
System.out.println("具体访问者B访问-->"+element.operationA());
}
public void visit(ConcreteElementB element)
{
System.out.println("具体访问者B访问-->"+element.operationB());
}
}
//抽象元素类
interface Element{
void accept(Visitor visitor);
}
//具体元素A类
class ConcreteElementA implements Element{
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String operationA(){
return "具体元素A的操作";
}
}
//具体元素B类
class ConcreteElementB implements Element{
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String operationB(){
return "具体元素B的操作";
}
}
//对象结构角色
class ObjectStructure{
private List<Element> list=new ArrayList<Element>();
public void accept(Visitor visitor){
Iterator<Element> i=list.iterator();
while(i.hasNext()){
((Element) i.next()).accept(visitor);
}
}
public void add(Element element){
list.add(element);
}
public void remove(Element element){
list.remove(element);
}
}
public class VisitorPattern
{
public static void main(String[] args)
{
ObjectStructure os=new ObjectStructure();
os.add(new ConcreteElementA());
os.add(new ConcreteElementB());
Visitor visitor=new ConcreteVisitorA();
os.accept(visitor);
System.out.println("------------------------");
visitor=new ConcreteVisitorB();
os.accept(visitor);
}
}
程序输出结果如下:
具体访问者A访问-->具体元素A的操作
具体访问者A访问-->具体元素B的操作
------------------------
具体访问者B访问-->具体元素A的操作
具体访问者B访问-->具体元素B的操作
访问者模式应用场景如下:
- 对象结构相对稳定,但其操作算法经常变化的程序。
- 对象结构中的对象需要提供多种不同且不相关的操作,而且要避免让这些操作的变化影响对象的结构。
- 对象结构包含很多类型的对象,希望对这些对象实施一些依赖于其具体类型的操作。
十、备忘录模式
备忘录模式主要面向的问题是:程序不同节点的状态无法被保存与回溯,该模式能记录一个对象的内部状态,当用户后悔时能撤销当前操作,使数据恢复到它原先的状态。如 Word、记事本、Photoshop、Eclipse 等软件在编辑时按 Ctrl+Z 组合键时能撤销当前操作,使文档恢复到之前的状态。
备忘录模式,又称快照模式,是指在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。
备忘录模式的主要角色如下:
- 发起人(Originator)角色:记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
- 备忘录(Memento)角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。
- 管理者(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。
以上结构图对应的代码实例如下:
//备忘录
class Memento{
private String state;
public Memento(String state){
this.state=state;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
//发起人
class Originator{
private String state;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public Memento createMemento(){
return new Memento(state);
}
public void restoreMemento(Memento memento){
this.setState(memento.getState());
}
}
//管理者
class Caretaker{
private Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
public class MementoPattern{
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
originator.setState("状态版本1");
System.out.println("初始状态:"+originator.getState());
//保存状态
caretaker.setMemento(originator.createMemento());
originator.setState("状态版本2");
System.out.println("新的状态:"+originator.getState());
//恢复状态
originator.restoreMemento(caretaker.getMemento());
System.out.println("恢复状态:"+originator.getState());
}
}
程序输出结果如下:
初始状态:状态版本1
新的状态:状态版本2
恢复状态:状态版本1
十一、解释器模式(了解)
解释器模式是指给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子。也就是说,用编译语言的方式来分析应用中的实例。解释器模式在实际中应用相对较少,在此只作了解。
解释器模式建立在语句有其规范的语法规则之上,即语句可以拆解为主语、谓语、宾语等语法树结构。
解释器模式主要角色如下:
- 抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()。
- 终结符表达式(Terminal Expression)角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。
- 非终结符表达式(Nonterminal Expression)角色:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。
- 环境(Context)角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。
- 客户端(Client):主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法。
以上结构图对应代码实例如下:
//抽象表达式类
interface AbstractExpression
{
public Object interpret(String info); //解释方法
}
//终结符表达式类
class TerminalExpression implements AbstractExpression
{
public Object interpret(String info)
{
//对终结符表达式的处理
}
}
//非终结符表达式类
class NonterminalExpression implements AbstractExpression
{
private AbstractExpression exp1;
private AbstractExpression exp2;
public Object interpret(String info)
{
//非对终结符表达式的处理
}
}
//环境类
class Context
{
private AbstractExpression exp;
public Context()
{
//数据初始化
}
public void operation(String info)
{
//调用相关表达式类的解释方法
}
}
解释器模式应用场景:
- 当语言的文法较为简单,且执行效率不是关键问题时。
- 当问题重复出现,且可以用一种简单的语言来进行表达时。
- 当一个语言需要解释执行,并且语言中的句子可以表示为一个抽象语法树的时候,如 XML 文档解释。
主要参考:http://c.biancheng.net/view