前言:
这是设计模式的第三期;继续根据实际开发应用场景解析这11种行为型设计模式,也是在实际开发中经常会用到的,希望给同学们带来帮助.
为了减少阅读疲劳 我会分成三部分详细诠释.
1.责任链模式(Chain of Responsibility)
概念:
它允许你将请求沿着处理者链进行传递,直到找到合适的处理者来处理该请求。每个处理者都可以决定是否处理请求,如果不能处理,则将请求传递给链中的下一个处理者。这种模式可以用来实现请求的多级处理,以及解耦请求发送者和接收者。
实际使用场景:
假设我们正在开发一个简单的日志记录系统,系统需要根据日志级别(DEBUG, INFO, WARNING, ERROR)来决定如何处理日志信息。我们可以使用责任链模式,让不同级别的处理器依次尝试处理日志,直到找到合适的处理器为止。
直接上代码:
a.抽象处理者
java
public interface Logger {
void log(int level, String message);
void setNextLogger(Logger nextLogger);
}
b.具体处理者
java
public class DebugLogger implements Logger {
private Logger nextLogger;
@Override
public void log(int level, String message) {
if (level == LogLevel.DEBUG) {
System.out.println("DEBUG: " + message);
} else if (nextLogger != null) {
nextLogger.log(level, message);
}
}
@Override
public void setNextLogger(Logger nextLogger) {
this.nextLogger = nextLogger;
}
}
c.客户端代码
java
public class ChainOfResponsibilityDemo {
public static void main(String[] args) {
// 构建责任链
Logger debugLogger = new DebugLogger();
Logger infoLogger = new InfoLogger();
Logger warningLogger = new WarningLogger();
Logger errorLogger = new ErrorLogger();
debugLogger.setNextLogger(infoLogger);
infoLogger.setNextLogger(warningLogger);
warningLogger.setNextLogger(errorLogger);
// 发出日志请求
debugLogger.log(LogLevel.DEBUG, "Debugging information.");
infoLogger.log(LogLevel.INFO, "Informational message.");
warningLogger.log(LogLevel.WARNING, "Warning occurred!");
errorLogger.log(LogLevel.ERROR, "An error has happened!");
}
}
java
// 假设的日志级别枚举简化表示
enum LogLevel {
DEBUG, INFO, WARNING, ERROR
}
说明
在这个例子中,每个日志处理器类(如DebugLogger)都实现了log方法,该方法首先判断当前日志级别是否匹配,如果匹配则处理日志,否则将请求转发给链中的下一个处理器。通过链式调用,请求会一直传递直到被处理或到达链的末端。
责任链模式的优势在于它提供了一种避免请求发送者与接收者耦合的方式,使得系统更易于扩展和维护。如果需要添加新的日志处理逻辑,只需添加一个新的处理者类并插入到链中即可,无需修改现有的处理者或客户端代码。
2.命令模式(Command)
概念:
它将请求封装成一个对象,从而让我们可用不同的请求、队列请求、或者日志请求。这样,命令的发出者和命令的执行者可以解耦,提高系统的灵活性。
实际使用场景:
假设我们正在开发一个智能家居系统,用户可以通过一个智能遥控器(RemoteControl)向家庭影院的各个设备(如电视、音响等)发送命令(如开关、调节音量等)。使用命令模式可以很好地设计这个系统,使得遥控器可以灵活地控制不同设备的不同操作,而且容易扩展新的设备或命令。
直接上代码:
a.抽象命令接口
java
public interface Command {
void execute();
void undo();
}
b.具体命令类
java
public class TVOnCommand implements Command {
private Television television;
public TVOnCommand(Television tv) {
this.television = tv;
}
@Override
public void execute() {
television.turnOn();
}
@Override
public void undo() {
television.turnOff();
}
}
c.接收者类
java
public class Television {
public void turnOn() {
System.out.println("TV is on.");
}
public void turnOff() {
System.out.println("TV is off.");
}
}
d.请求者(调用者)类
java
public class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
public void pressUndoButton() {
command.undo();
}
}
e.客户端代码
java
public class CommandPatternDemo {
public static void main(String[] args) {
Television tv = new Television();
Command tvOnCommand = new TVOnCommand(tv);
Command tvOffCommand = new TVOffCommand(tv);
RemoteControl remoteControl = new RemoteControl();
remoteControl.setCommand(tvOnCommand);
remoteControl.pressButton(); // 执行打开电视命令
remoteControl.setCommand(tvOffCommand);
remoteControl.pressUndoButton(); // 执行撤销命令,关闭电视
}
}
总结
在这个例子中,命令模式通过将动作请求封装成命令对象,实现了发送者和接收者的解耦。这样,我们不仅可以灵活地增加新的命令或接收者,而且可以通过增加新的命令类来支持撤销操作,而不需要修改现有类的代码。此外,命令模式还便于实现日志、事务等功能,因为它提供了一种统一的处理请求的方式。
3.解释器模式(Interpreter)
概念:
它定义了如何使用表达式来解释一个语言中的句子。这种模式实现了文法表达式和其在解释器中的表示,使我们能够对这些句子进行解释和计算。解释器模式通常用于编译器、运算表达式解析、符号处理系统等领域。
实际使用场景:
假设我们正在开发一个简单的计算器程序,它能够解析和计算算术表达式(仅包含加减乘除四则运算)。使用解释器模式,我们可以定义一个表达式接口和一系列实现该接口的具体表达式类,用于解释和计算输入的算术表达式。
直接上代码:
a.抽象表达式
java
public interface Expression {
int interpret();
}
b.终结符表达式
java
public class TerminalExpression implements Expression {
private int value;
public TerminalExpression(int value) {
this.value = value;
}
@Override
public int interpret() {
return value;
}
}
c.非终结符表达式
java
public class PlusExpression implements Expression {
private Expression left, right;
public PlusExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret() {
return left.interpret() + right.interpret();
}
}
java
public class MinusExpression implements Expression {
private Expression left, right;
public MinusExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret() {
return left.interpret() - right.interpret();
}
}
d.客户端代码
java
public class InterpreterPatternDemo {
public static void main(String[] args) {
Expression five = new TerminalExpression(5);
Expression three = new TerminalExpression(3);
Expression plus = new PlusExpression(five, three);
Expression two = new TerminalExpression(2);
Expression minus = new MinusExpression(plus, two);
System.out.println("Result of (5 + 3) - 2: " + minus.interpret()); // 输出结果
}
}
解释
在这个例子中,我们通过解释器模式定义了一个简单的算术表达式解释器。TerminalExpression类代表了数值(终结符表达式),而PlusExpression和MinusExpression类分别代表了加法和减法操作(非终结符表达式)。客户端代码通过组合这些表达式类实例,构建了一个表达式树来表示(5 + 3) - 2这个算术表达式,然后调用interpret方法来计算表达式的值。
解释器模式适合于那些语言简单且易于用规则表达的问题。对于复杂的语言或者频繁变化的文法规则,解释器模式的维护成本可能会比较高。
4.迭代器模式(Iterator)
概念:
它提供了一种访问集合元素的方式,而又不暴露集合的内部结构。迭代器模式定义了一个迭代器接口,该接口负责遍历集合中的元素,这样就可以不依赖于集合的具体实现来访问集合中的元素。
实际使用场景:
假设我们正在开发一个图书管理系统,系统中包含多个书架,每个书架上摆放着若干本书。为了方便地遍历所有书架上的书籍,我们可以使用迭代器模式来设计这个系统,使得客户端代码无需了解书架的内部结构就能遍历所有书籍。
直接上代码:
a.抽象迭代器接口
java
public interface Iterator<T> {
boolean hasNext();
T next();
}
b.具体迭代器
java
public class BookShelfIterator implements Iterator<Book> {
private final BookShelf bookShelf;
private int index;
public BookShelfIterator(BookShelf bookShelf) {
this.bookShelf = bookShelf;
this.index = 0;
}
@Override
public boolean hasNext() {
return index < bookShelf.getLength();
}
@Override
public Book next() {
if (!hasNext()) throw new NoSuchElementException();
return bookShelf.getBookAt(index++);
}
}
c.聚集接口
java
public interface Aggregate<T> {
Iterator<T> iterator();
}
d.具体聚集
java
public class BookShelf implements Aggregate<Book> {
private final List<Book> books;
private int last = 0;
public BookShelf(int maxsize) {
this.books = new ArrayList<>(maxsize);
}
public Book getBookAt(int index) {
return books.get(index);
}
public void appendBook(Book book) {
if (last >= books.size()) {
books.add(book);
} else {
books.set(last, book);
}
last++;
}
public int getLength() {
return books.size();
}
@Override
public Iterator<Book> iterator() {
return new BookShelfIterator(this);
}
}
e.具体元素
java
public class Book {
private String name;
public Book(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
f.客户端代码
java
public class IteratorPatternDemo {
public static void main(String[] args) {
BookShelf bookShelf = new BookShelf(4);
bookShelf.appendBook(new Book("Design Patterns"));
bookShelf.appendBook(new Book("Effective Java"));
bookShelf.appendBook(new Book("Clean Code"));
Iterator<Book> it = bookShelf.iterator();
while (it.hasNext()) {
Book book = it.next();
System.out.println(book.getName());
}
}
}
解释
在这个例子中,BookShelf类实现了Aggregate接口,并提供了iterator()方法来返回一个BookShelfIterator实例,该迭代器负责遍历书架上的书籍。客户端代码通过调用iterator()方法获得迭代器,并使用迭代器的hasNext()和next()方法来遍历所有的书籍。迭代器模式使得遍历集合的操作与集合的具体实现相分离,提高了代码的灵活性和可维护性。
好了以上就是行为型设计模式的4种具体设计模式的使用场景;第二,第三部分下期见.