目录
1.访问者模式
2.备忘录模式
3.解析器模式
一、访问者模式(Visitor)
用于某种数据结构中的各个元素的操作分离出来封装成独立的类,使不改变数据结构的前提下可以添加新的操作,为数据结构中每个元素提供多种访问方式。
核心角色:
- (1)抽象访问者角色(Visitor):定义一个访问具体元素的接口。为每个具体元素类对应一个访问操作visit(),该操作中的类型标识了被访问的具体元素。
- (2)具体访问者角色(Concrete Visitor):实现抽象访问者角色中声明的访问操作,确定访问者访问一个元素时该做什么。
- (3)抽象元素角色(Element):声明一个包含接受操作accept()的接口,被接受的访问者对象作为accept()方法的参数。
- (4)具体元素角色(Concrete Element):实现抽象元素角色提供的accept()操作,其方法体通常都是visitor.visit(this),另外具体元素中可能还包含本身业务逻辑的相关操作。
- (5)对象结构角色(Object Structure):一个包含元素角色的容器,提供让访问者对象遍历容器中所有元素的方法,通常有List、Set、Map等聚合实现。
优点:
- (1)扩展性能好。不修改对象结构的元素情况下,添加新的功能。
- (2)复用性好。可以通过访问者定义整个对象结构通用的功能。
- (3)灵活性好。将数据结构与作用域结构上的操作解耦,使操作可以相对自由地演化而不影响系统的数据结构。
- (4)符合单一职责原则。把相关的行为封装在一起,构成一个访问者,使每个访问者功能都比较单一
缺点:
- (1)增加新的元素类很困难。每增加一个新的元素,都要在每一个具体访问者类中增加相应的具体操作。违背了开闭原则。
- (2)破坏封装。具体元素对访问者公布细节。
- (3)违反了依赖倒置原则。依赖具体类,而没有依赖抽象类。
public class textVisitor {
public static void main(String[] args) {
// TODO Auto-generated method stub
ObjectStructure os = new ObjectStructure();
os.add(new ConcreteElementA());
os.add(new ConcreteElementB());
Visitor visitor = new ConcreteVisitorA();
os.accpet(visitor);
System.out.println("---------");
os.accpet(visitor);
}
}
//抽象访问者
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{
@Override
public void visit(ConcreteElementA element) {
System.out.println("具体访问者B访问-->"+element.operationA());
}
@Override
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 accpet(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);
}
}
二、备忘录模式(Memento)
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便将该对象恢复到原来保存的状态。又叫快照模式。
核心角色:
- (1)发起人角色(Originator):记录当前时刻内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,可以访问备忘录里所有的信息。
- (2)备忘录角色(Memento):负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。
- (3)管理者角色(Caretaker):对备忘录进行管理,提供保存于获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。
优点:
- (1)提供一种可以恢复状态的封装。可以恢复到某个历史操作
- (2)实现了内部状态的封装。除了创建的发起人之外,其他对象不能够访问。
- (3)简化了发起人类。发起人不需要管理和保存其内部状态的各个备份,所有状态信息都保存在备忘录中,并由管理者进行管理,符合单一职责原则。
缺点:
- (1)资源消耗大。如果保存的内部状态信息过多或者特别繁杂,将会导致占用比较大的内存资源。
public class textMemento {
public static void main(String[] args) {
// TODO Auto-generated method stub
Originator or = new Originator();
Caretaker cr = new Caretaker();
or.setState("s0");
System.out.println("初始状态"+or.getState());
cr.setMemento(or.createMemento()); //保存状态
or.setState("s1");//更新状态
System.out.println("更新状态"+or.getState());
or.restoreMemento(cr.getMemento());//恢复
System.out.println("恢复状态"+or.getState());
}
}
//备忘录
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 m) {
this.setState(m.getState());
}
}
//管理者
class Caretaker{
private Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
三、解析器模式(Interpreter)
给对象一个语言,并定义该语言的文法表示,再设计一个解析器来解析语言中的句子。就是用编译语言的方式来分析应用中的实例。实现了文法表达式处理的接口,该接口解析一个特定的上下文。
核心角色:
- (1)抽象表达式角色(Abstract Expression):定义解析器的接口,约定解析器的解析操作,主要包含解析方法interpret();
- (2)终结符表达式角色(Terminal Expression):抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。
- (3)非终结符表达式角色(Nonterminal Expression):也是抽象表达式的子类,用来实现文法中与非终结符相关的操作。
- (4)环境角色(Context):包含各个解析器需要的数据或者是公共的功能,一般用来传递被所有解析器共享的数据,后面的解析器可以从这里获取这些值。
- (5)客户端(Client):将需要分析的句子或表达式转换成使用解析器对象描述的抽象语法树,然后调用解析器的解析方法,当然也可以通过环境角色简接访问解析器的解析方法。
优点:
- (1)扩展性好。通过继承等机制来改变或扩展文法。
- (2)容易实现。在语法树中的每个表达式节点类都相似的,所以实现其文法容易。
缺点:
- (1)执行效率低。使用大量的循环和递归调用。
- (2)会引起类膨胀。每条规则至少需要定义一个类,包含的文法规则很多时,类的个数将急剧增加,导致系统难以管理和维护。
- (3)可应用场景少。
//抽象表达式类
interface AbstractExpression{
public Object interpret(String info);//解析方法
}
//终结符表达式
class TerminalExpression implements AbstractExpression{
@Override
public Object interpret(String info) {
//对终结符表达式处理
return null;
}
}
//非终结符表达式
class NonterminalExpression implements AbstractExpression{
@Override
public Object interpret(String info) {
//对非终结符表达式处理
return null;
}
}
//环境类
class Context{
private AbstractExpression exp;
public Context() { //数据初始化
}
public void operation(String info) {
//调用相关表达式类的解析方法
}
}