一、前言
在前三篇 《深入了解JAVA中的23种设计模式(一)- 创建型模式》 《深入了解JAVA中的23种设计模式(二)- 结构型模式》 《深入了解JAVA中的23种设计模式(三)- 行为型模式(上)》 中介绍了Java中的23种设计模式的创建型模式、结构型模式与行为型模式中的一些设计模式,本文将继续讲解行为型模式剩下的设计模式。
二、行为型模式(下)
1. 备忘录模式
1.1 简介
在不破坏封装性的前提下捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后可以将对象恢复到原先保存的状态。
1.2 使用场景
需要保存和恢复数据的相关状态场景。
提供一个可回滚(rollback)的操作。
需要监控的副本场景中。
数据库连接的事务管理就是用的备忘录模式。
1.3 代码示例
/ 发起
public class Originator {
private String state;
public void setState(String state) {
this.state = state;
}
public String getState() {
return state;
}
// 创建备忘录
public Memento createMemento() {
return new Memento(state);
}
// 使用备忘录恢复状态
public void restoreMemento(Memento memento) {
this.state = memento.getState();
}
}
// 备忘录
public class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
// 管理者
public class Caretaker {
private Memento memento;
public void setMemento(Memento memento) {
this.memento = memento;
}
public Memento getMemento() {
return memento;
}
}
2. 状态模式
2.1 简介
允许一个对象在其内部状态改变时改变它的行为,对象看起来好像修改了它的类。其核心思想是将状态与行为绑定,不同的状态对应不同的行为。当控制一个对象状态的条件表达式过于复杂时,状态模式可以将状态的判断逻辑转移到表示不同状态的一系列类中,从而简化复杂的判断逻辑。
2.2 使用场景
当对象的行为与其当前状态密切相关,且需要在运行时根据状态改变行为时,可以使用状态模式。
当一个操作中含有庞大的多分支结构,并且这些分支取决于对象的状态时,状态模式可以简化代码并提高可维护性。
当需要避免使用大量的条件语句来控制对象的行为时,状态模式可以提供一种更加优雅的解决方案。
2.3 代码示例
/抽象状态角色
public abstract class Status {
//定义一个角色,提供子类访问
protected Context context;
//设置角色
public void setContext(Context _context){
this.context = _context;
}
//行为1
public abstract void handle1();
//行为2
public abstract void handle2();
}
3. 访问者模式
3.1 简介
它表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。简单来说,访问者模式将数据操作与数据结构分离,使得在不修改数据结构的前提下,能为数据结构中的每个元素增加新的操作。
3.2 使用场景
当一个对象结构包含多个不同类型的对象,并且需要对这些对象执行不同的操作时,可以使用访问者模式。
当需要在不修改对象结构的情况下,添加新的操作或行为到对象中时,可以使用访问者模式。通过添加新的访问者类,可以实现新的操作,而无需修改现有的对象结构。
当对象结构中的对象类型相对稳定,但经常需要添加新的操作时,可以使用访问者模式。访问者模式使得添加新的操作变得简单,只需要创建新的访问者类即可。
当对象结构中的对象类型很少改变,但经常需要在这些对象上执行复杂操作时,可以使用访问者模式。访问者模式可以将复杂的操作分离出来,使得对象结构更加清晰和简单。
3.3 代码示例
// 访问者接口
interface Visitor {
void visit(ElementA elementA);
void visit(ElementB elementB);
}
// 具体访问者类
class ConcreteVisitor implements Visitor {
@Override
public void visit(ElementA elementA) {
System.out.println("访问 ElementA: " + elementA.getOperationA());
}
@Override
public void visit(ElementB elementB) {
System.out.println("访问 ElementB: " + elementB.getOperationB());
}
}
// 元素接口
interface Element {
void accept(Visitor visitor);
}
// 具体元素类 A
class ElementA implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String getOperationA() {
return "ElementA 的操作";
}
}
// 具体元素类 B
class ElementB implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
public String getOperationB() {
return "ElementB 的操作";
}
}
// 对象结构类
class ObjectStructure {
private List<Element> elements = new ArrayList<>();
public void addElement(Element element) {
elements.add(element);
}
public void accept(Visitor visitor) {
for (Element element : elements) {
element.accept(visitor);
}
}
}
4. 中介者模式
4.1 简介
该模式用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
4.2 使用场景
系统中对象之间存在复杂的引用关系,系统结构混乱且难以理解。
一个对象由于引用了其他很多对象并且直接和这些对象通信,导致难以复用该对象。想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。
4.3 代码示例
// 抽象中介者
public interface Mediator {
void register(Colleague colleague);
void relay(Colleague colleague, String message);
}
// 具体中介者
public class ConcreteMediator implements Mediator {
private List<Colleague> colleagues = new ArrayList<>();
@Override
public void register(Colleague colleague) {
if (!colleagues.contains(colleague)) {
colleagues.add(colleague);
}
colleague.setMediator(this);
}
@Override
public void relay(Colleague colleague, String message) {
for (Colleague col : colleagues) {
if (!col.equals(colleague)) {
col.receive(message);
}
}
}
}
// 抽象同事类
public abstract class Colleague {
protected Mediator mediator;
public void setMediator(Mediator mediator) {
this.mediator = mediator;
}
public abstract void receive(String message);
}
// 具体同事类
public class ConcreteColleague extends Colleague {
@Override
public void receive(String message) {
System.out.println("ConcreteColleague received message: " + message);
}
public void send(String message) {
mediator.relay(this, message);
}
}
5. 解释器模式
5.1 简介
提供了一种方式来定义语言的文法,并且建立一个解释器来解释该语言中的句子。这个模式定义了一个表示文法的类接口,以及一个解释这些文法的解释器接口。
抽象表达式(AbstractExpression):声明一个抽象的解释操作,这个接口为所有的具体表达式定义了一个统一的接口。
终结符表达式(TerminalExpression):实现了抽象表达式接口,并包含对文法中终结符的解释。
非终结符表达式(NonterminalExpression):实现了抽象表达式接口,并包含对文法中非终结符的解释。非终结符表达式通常还包含对其他表达式的引用。
环境(Context):包含解释器之外的一些全局信息,一般用来存储文法中各个终结符所对应的具体值。
客户端(Client):构建文法对应的抽象语法树,并调用解释器来解释文法。
5.2 使用场景
当有一个语言需要解释执行,并且该语言中的句子有比较简单的语法规则时,可以使用解释器模式。
当一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象语法树时,可以使用解释器模式。
当一个简单语法需要解释的场景也可以考虑使用解释器模式,如配置文件解析、数学表达式解析等。
5.3 代码示例
// 抽象表达式
interface Expression {
int interpret(Context context);
}
// 终结符表达式 - 数字
class NumberExpression implements Expression {
private int value;
public NumberExpression(int value) {
this.value = value;
}
@Override
public int interpret(Context context) {
return value;
}
}
// 非终结符表达式 - 加法
class AdditionExpression implements Expression {
private Expression left;
private Expression right;
public AdditionExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret(Context context) {
return left.interpret(context) + right.interpret(context);
}
}
设计模式不是公式,没必要去死记硬背每一种模式,更重要的是了解它的抽象思想,以及应用设计模式怎么更好地解决问题,可以达成什么效果。理论虽多,但是我们要把它掌握的话,对于我们的实际开发来说会解决不少的问题。