Java 设计模式:行为型模式详解
行为型模式关注对象之间的交互和算法,它们可以提高代码的可扩展性、可复用性和可维护性。以下将详细讲解六种常见的行为型模式:责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式。
1. 责任链模式(Chain of Responsibility)
定义: 责任链模式将请求处理的对象连接成一条链,沿着链传递请求,直到某个对象处理它。
优势:
- 减轻发送者和接收者的耦合: 发送者无需知道请求的具体处理者,只需发送请求,链上的对象会自动处理。
- 灵活的请求处理: 可以动态添加或移除链上的对象,方便扩展。
- 简化代码逻辑: 将请求处理逻辑分散到不同的对象中,提高代码可读性。
实例:
假设我们要处理员工的请假申请,需要审批流程,不同职位的人员有不同的审批权限:
// 审批者接口
interface Approver {
void approve(LeaveRequest request);
void setNextApprover(Approver approver);
}
// 具体审批者类
class Manager implements Approver {
private Approver nextApprover;
@Override
public void approve(LeaveRequest request) {
if (request.getDays() <= 3) {
System.out.println("Manager approved the leave request.");
} else {
if (nextApprover != null) {
nextApprover.approve(request);
} else {
System.out.println("Leave request rejected.");
}
}
}
@Override
public void setNextApprover(Approver approver) {
this.nextApprover = approver;
}
}
class Director implements Approver {
private Approver nextApprover;
@Override
public void approve(LeaveRequest request) {
if (request.getDays() <= 7) {
System.out.println("Director approved the leave request.");
} else {
if (nextApprover != null) {
nextApprover.approve(request);
} else {
System.out.println("Leave request rejected.");
}
}
}
@Override
public void setNextApprover(Approver approver) {
this.nextApprover = approver;
}
}
// 请假申请类
class LeaveRequest {
private int days;
public LeaveRequest(int days) {
this.days = days;
}
public int getDays() {
return days;
}
}
public class ChainOfResponsibilityExample {
public static void main(String[] args) {
Manager manager = new Manager();
Director director = new Director();
manager.setNextApprover(director);
LeaveRequest request1 = new LeaveRequest(2); // Manager审批
LeaveRequest request2 = new LeaveRequest(5); // Director审批
LeaveRequest request3 = new LeaveRequest(10); // Rejected
manager.approve(request1);
manager.approve(request2);
manager.approve(request3);
}
}
2. 命令模式(Command)
定义: 命令模式将请求封装为对象,从而使你能够参数化客户端,将请求排队或记录请求日志,并支持可撤销的操作。
优势:
- 解耦调用者和接收者: 调用者无需了解具体操作的实现细节,只需执行命令对象。
- 可扩展性强: 可以很容易地添加新的命令,无需修改调用者的代码。
- 易于撤销操作: 命令对象可以保存操作的上下文,方便撤销。
实例:
假设我们要实现一个简单的文本编辑器,用户可以使用不同的命令来操作文本:
// 命令接口
interface Command {
void execute();
void undo();
}
// 具体命令类
class InsertCommand implements Command {
private String text;
private Editor editor;
public InsertCommand(String text, Editor editor) {
this.text = text;
this.editor = editor;
}
@Override
public void execute() {
editor.insertText(text);
}
@Override
public void undo() {
editor.deleteText(text);
}
}
class DeleteCommand implements Command {
private String text;
private Editor editor;
public DeleteCommand(String text, Editor editor) {
this.text = text;
this.editor = editor;
}
@Override
public void execute() {
editor.deleteText(text);
}
@Override
public void undo() {
editor.insertText(text);
}
}
// 文本编辑器类
class Editor {
private String text;
public void insertText(String text) {
this.text += text;
}
public void deleteText(String text) {
this.text = this.text.replace(text, "");
}
public String getText() {
return text;
}
}
public class CommandExample {
public static void main(String[] args) {
Editor editor = new Editor();
InsertCommand insertCommand = new InsertCommand("Hello, ", editor);
DeleteCommand deleteCommand = new DeleteCommand("Hello, ", editor);
insertCommand.execute(); // 插入文本
System.out.println(editor.getText());
deleteCommand.execute(); // 删除文本
System.out.println(editor.getText());
deleteCommand.undo(); // 撤销删除操作
System.out.println(editor.getText());
}
}
3. 解释器模式(Interpreter)
定义: 解释器模式提供了一种方式来定义语言的文法,并使用该文法来解析和执行语言中的句子。
优势:
- 易于扩展: 可以方便地添加新的语法规则,而无需修改现有的解释器代码。
- 代码可读性好: 使用解释器模式可以将复杂的解析逻辑分解成更小的、易于理解的组件。
实例:
假设我们要实现一个简单的表达式计算器,可以解析和计算加减乘除运算:
// 表达式接口
interface Expression {
int interpret();
}
// 具体表达式类
class NumberExpression implements Expression {
private int number;
public NumberExpression(int number) {
this.number = number;
}
@Override
public int interpret() {
return number;
}
}
class AddExpression implements Expression {
private Expression left;
private Expression right;
public AddExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret() {
return left.interpret() + right.interpret();
}
}
class SubtractExpression implements Expression {
private Expression left;
private Expression right;
public SubtractExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret() {
return left.interpret() - right.interpret();
}
}
// 表达式解析器类
class ExpressionParser {
public Expression parse(String expression) {
String[] parts = expression.split(" ");
Expression result = new NumberExpression(Integer.parseInt(parts[0]));
for (int i = 1; i < parts.length; i += 2) {
String operator = parts[i];
int number = Integer.parseInt(parts[i + 1]);
if (operator.equals("+")) {
result = new AddExpression(result, new NumberExpression(number));
} else if (operator.equals("-")) {
result = new SubtractExpression(result, new NumberExpression(number));
}
}
return result;
}
}
public class InterpreterExample {
public static void main(String[] args) {
ExpressionParser parser = new ExpressionParser();
Expression expression = parser.parse("1 + 2 - 3");
int result = expression.interpret();
System.out.println("Result: " + result); // Result: 0
}
}
4. 迭代器模式(Iterator)
定义: 迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而无需暴露该对象的内部表示。
优势:
- 访问聚合对象更方便: 迭代器提供统一的访问接口,简化了访问操作。
- 易于扩展: 可以方便地添加新的迭代器,而无需修改聚合对象本身。
- 提高代码可读性: 迭代器模式将遍历逻辑从聚合对象中分离出来,提高代码可读性。
实例:
假设我们要实现一个学生列表,可以遍历列表中的每个学生:
// 迭代器接口
interface Iterator {
boolean hasNext();
Student next();
}
// 具体迭代器类
class StudentIterator implements Iterator {
private Student[] students;
private int index;
public StudentIterator(Student[] students) {
this.students = students;
}
@Override
public boolean hasNext() {
return index < students.length;
}
@Override
public Student next() {
return students[index++];
}
}
// 学生类
class Student {
private String name;
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
// 学生列表类
class StudentList {
private Student[] students;
public StudentList(Student[] students) {
this.students = students;
}
public Iterator getIterator() {
return new StudentIterator(students);
}
}
public class IteratorExample {
public static void main(String[] args) {
Student[] students = {
new Student("Alice"),
new Student("Bob"),
new Student("Charlie")
};
StudentList studentList = new StudentList(students);
Iterator iterator = studentList.getIterator();
while (iterator.hasNext()) {
Student student = (Student) iterator.next();
System.out.println(student.getName());
}
}
}
5. 中介者模式(Mediator)
定义: 中介者模式定义一个对象来封装一系列对象之间的交互。中介者使各对象不需要显式地相互引用,从而可以松散地耦合。
优势:
- 降低耦合度: 对象之间无需直接通信,降低耦合度,提高代码可维护性。
- 简化交互逻辑: 中介者可以集中处理对象之间的交互逻辑,简化代码逻辑。
- 易于扩展: 可以方便地添加新的对象,而无需修改其他对象代码。
实例:
假设我们要实现一个聊天室,用户可以互相发送消息,但无需直接引用其他用户:
// 聊天室接口
interface ChatRoom {
void sendMessage(String message, User sender);
}
// 具体聊天室类
class ConcreteChatRoom implements ChatRoom {
@Override
public void sendMessage(String message, User sender) {
for (User user : User.getUsers()) {
if (user != sender) {
user.receiveMessage(sender, message);
}
}
}
}
// 用户接口
interface User {
void sendMessage(String message);
void receiveMessage(User sender, String message);
}
// 具体用户类
class ConcreteUser implements User {
private String name;
private ChatRoom chatRoom;
public ConcreteUser(String name, ChatRoom chatRoom) {
this.name = name;
this.chatRoom = chatRoom;
}
@Override
public void sendMessage(String message) {
chatRoom.sendMessage(message, this);
}
@Override
public void receiveMessage(User sender, String message) {
System.out.println(sender.getName() + "->" + name + ": " + message);
}
public String getName() {
return name;
}
}
public class MediatorExample {
public static void main(String[] args) {
ChatRoom chatRoom = new ConcreteChatRoom();
User user1 = new ConcreteUser("Alice", chatRoom);
User user2 = new ConcreteUser("Bob", chatRoom);
user1.sendMessage("Hello, Bob!");
user2.sendMessage("Hi, Alice!");
}
}
6. 备忘录模式(Memento)
定义: 备忘录模式在不破坏封装性的前提下,捕获并外部化一个对象的内部状态,以便在以后恢复到这个状态。
优势:
- 可撤销操作: 可以方便地撤销对对象的修改,恢复到之前的状态。
- 保护封装性: 备忘录模式不会暴露对象的内部状态,保持封装性。
- 可扩展性强: 可以方便地添加新的状态保存功能,而无需修改原始对象。
实例:
假设我们要实现一个游戏存档功能,可以保存游戏中的玩家状态,以便以后恢复:
// 备忘录接口
interface Memento {
}
// 具体备忘录类
class PlayerMemento implements Memento {
private int health;
private int level;
public PlayerMemento(int health, int level) {
this.health = health;
this.level = level;
}
public int getHealth() {
return health;
}
public int getLevel() {
return level;
}
}
// 玩家接口
interface Player {
Memento saveState();
void restoreState(Memento memento);
}
// 具体玩家类
class ConcretePlayer implements Player {
private int health;
private int level;
public ConcretePlayer(int health, int level) {
this.health = health;
this.level = level;
}
@Override
public Memento saveState() {
return new PlayerMemento(health, level);
}
@Override
public void restoreState(Memento memento) {
PlayerMemento savedState = (PlayerMemento) memento;
this.health = savedState.getHealth();
this.level = savedState.getLevel();
}
public int getHealth() {
return health;
}
public int getLevel() {
return level;
}
}
public class MementoExample {
public static void main(String[] args) {
Player player = new ConcretePlayer(100, 1);
Memento savedState = player.saveState(); // 保存游戏状态
// 进行游戏操作,玩家状态发生改变
player.health -= 20;
player.level += 1;
System.out.println("Current health: " + player.getHealth());
System.out.println("Current level: " + player.getLevel());
player.restoreState(savedState); // 恢复到之前的状态
System.out.println("Restored health: " + player.getHealth());
System.out.println("Restored level: " + player.getLevel());
}
}
总结:
行为型模式可以有效地提高代码的可扩展性、可复用性和可维护性。选择合适的行为型模式,可以使你的代码更加清晰、灵活、易于维护。在实际开发中,需要根据具体的场景选择合适的模式。