1.解释器模式(Interpreter Pattern)
目的: 解释器模式是一种行为设计模式,它提供了一种方法来表示语言的语法或表达式,并定义一个解释器来解释这些语句的含义。该模式主要应用于解决小型语言或者表达式的解析问题,它描述了如何为简单的语言定义一个语法表示,并且设计一个解释器来解释这些语法结构。
结构:
AbstractExpression
(抽象表达式):定义解释器的接口,声明一个解释方法。TerminalExpression
(终结符表达式):实现了抽象表达式,对应文法中的基本符号,能够直接解释。NonterminalExpression
(非终结符表达式):也是抽象表达式的实现,但是可能包含其他表达式,对应文法中的复合结构,通常会根据文法规则调用其他表达式进行解释。Context
(上下文):包含了解析过程中需要的数据和环境信息,通常作为解释器的参数传入。
示例场景: 编写一个简单的数学表达式解析器,其中数字和运算符可以作为终结符表达式,而加减乘除的运算表达式可以作为非终结符表达式。
// 抽象表达式
abstract class Expression {
abstract int interpret(Context context);
}
// 终结符表达式(数字)
class NumberExpression extends Expression {
private int number;
public NumberExpression(int number) {
this.number = number;
}
@Override
int interpret(Context context) {
return number;
}
}
// 终结符表达式(变量)
class VariableExpression extends Expression {
private String variableName;
public VariableExpression(String variableName) {
this.variableName = variableName;
}
@Override
int interpret(Context context) {
return context.lookup(variableName);
}
}
// 非终结符表达式(加法)
class AddExpression extends Expression {
private Expression left, right;
public AddExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
int interpret(Context context) {
return left.interpret(context) + right.interpret(context);
}
}
// 上下文
class Context {
private Map<String, Integer> variables;
public Context(Map<String, Integer> variables) {
this.variables = variables;
}
public int lookup(String key) {
return variables.get(key);
}
}
// 客户端代码
public class InterpreterPatternDemo {
public static void main(String[] args) {
Context context = new Context(Map.of("x", 10, "y", 20));
Expression expr = new AddExpression(
new NumberExpression(5),
new AddExpression(
new VariableExpression("x"),
new VariableExpression("y")
)
);
int result = expr.interpret(context);
System.out.println("Result: " + result); // 输出:35
}
}
2.访问者模式(Visitor Pattern)
目的: 访问者模式是一种行为设计模式,它允许你在不改变现有类的基础上增加新的操作。访问者模式通过分离数据结构和作用于数据结构上的操作来达到这一目的,数据结构对象拥有接受访问者的通用接口,而访问者则持有对元素执行操作的方法。
结构:
Element
(元素):定义一个接受操作的接口,一般是一个抽象类,声明一个accept
方法,接收一个访问者对象作为参数。ConcreteElement
(具体元素):实现元素接口,提供具体的接受访问者方法的实现。Visitor
(访问者):声明访问者可以访问的元素对象所对应的各个操作。ConcreteVisitor
(具体访问者):实现对元素的操作,每个具体访问者类重写对每个元素的操作方法。
示例场景: 在编译器中分析抽象语法树(AST),不同的访问者可以完成不同的任务,如类型检查、代码生成等。使用访问者模式解析文件系统对象:
// 被访问的对象接口
interface FileItem {
void accept(FileVisitor visitor);
}
// 具体被访问的对象
class File implements FileItem {
String name;
public File(String name) {
this.name = name;
}
@Override
public void accept(FileVisitor visitor) {
visitor.visitFile(this);
}
}
class Directory implements FileItem {
String name;
List<FileItem> items;
public Directory(String name) {
this.name = name;
this.items = new ArrayList<>();
}
public void addItem(FileItem item) {
items.add(item);
}
@Override
public void accept(FileVisitor visitor) {
visitor.preVisitDirectory(this);
for (FileItem item : items) {
item.accept(visitor);
}
visitor.postVisitDirectory(this);
}
}
// 访问者接口
interface FileVisitor {
void visitFile(File file);
void preVisitDirectory(Directory dir);
void postVisitDirectory(Directory dir);
}
// 具体访问者,打印文件名
class PrintFileNameVisitor implements FileVisitor {
@Override
public void visitFile(File file) {
System.out.println("File: " + file.name);
}
@Override
public void preVisitDirectory(Directory dir) {
System.out.println("Entering directory: " + dir.name);
}
@Override
public void postVisitDirectory(Directory dir) {
System.out.println("Leaving directory: " + dir.name);
}
}
// 客户端代码
public class VisitorPatternDemo {
public static void main(String[] args) {
Directory root = new Directory("root");
Directory dir1 = new Directory("dir1");
File file1 = new File("file1.txt");
root.addItem(dir1);
dir1.addItem(file1);
PrintFileNameVisitor visitor = new PrintFileNameVisitor();
root.accept(visitor);
}
}
// 输出:
// Entering directory: root
// Entering directory: dir1
// File: file1.txt
// Leaving directory: dir1
// Leaving directory: root
3.建造者模式(Builder Pattern)
目的: 建造者模式是一种创建型设计模式,主要用于分步骤创建复杂对象,隐藏对象的创建细节,使得同样的创建过程可以创建不同的表示。它主要是为了解决对象的创建过程复杂性问题,将对象的构建和表示分离,从而使得客户端不需要知道具体构建细节就可以构建复杂对象。
结构:
Builder
(抽象建造者):定义一个抽象接口,用于规定产品对象各个部分的建造顺序以及建造方法。ConcreteBuilder
(具体建造者):继承抽象建造者,实现抽象接口,具体完成产品的各个部件的建造,同时提供一个返回产品的方法。Director
(指挥者):调用具体建造者的建造方法来创建产品,指导具体建造流程。Product
(产品):定义产品的接口和属性。
示例场景: 构建复杂对象如计算机配置,不同的具体建造者可以按照不同的配置规格(如CPU、内存、硬盘等)创建出不同的计算机实例。构建复杂的披萨订单:
// 披萨产品
class Pizza {
private String size;
private List<String> toppings;
private boolean cheeseExtra;
// 私有构造函数,仅由建造者类访问
private Pizza(PizzaBuilder builder) {
this.size = builder.size;
this.toppings = builder.toppings;
this.cheeseExtra = builder.cheeseExtra;
}
// 获取披萨的信息
public String getSize() {
return size;
}
public List<String> getToppings() {
return Collections.unmodifiableList(toppings);
}
public boolean isCheeseExtra() {
return cheeseExtra;
}
// 披萨建造者
public static class PizzaBuilder {
private String size;
private List<String> toppings = new ArrayList<>();
private boolean cheeseExtra;
public PizzaBuilder setSize(String size) {
this.size = size;
return this;
}
public PizzaBuilder addTopping(String topping) {
this.toppings.add(topping);
return this;
}
public PizzaBuilder withExtraCheese(boolean extra) {
this.cheeseExtra = extra;
return this;
}
// 创建最终产品
public Pizza build() {
return new Pizza(this);
}
}
}
// 客户端代码
public class BuilderPatternDemo {
public static void main(String[] args) {
Pizza pizza = new Pizza.PizzaBuilder()
.setSize("Large")
.addTopping("Pepperoni")
.addTopping("Mushrooms")
.withExtraCheese(true)
.build();
System.out.println("Size: " + pizza.getSize());
System.out.println("Toppings: " + pizza.getToppings().toString());
System.out.println("Extra Cheese: " + pizza.isCheeseExtra());
}
}
// 输出:
// Size: Large
// Toppings: [Pepperoni, Mushrooms]
// Extra Cheese: true