行为型模式关注流程控制。
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象无法完成的任务,涉及算法与对象间职责的分配。
- 类行为模式:采用继承机制来在类间分派行为
- 对象行为模式:采用组合或聚合在对象间分配行为
行为模式包括 11 种:模板方法模式、解释器模式、策略模式、命令模式、职责链模式、状态模式、观察者模式、中介者模式、迭代器模式、访问者模式、备忘录模式。仅前两种属于类行为模式。
模板方法模式
算法步骤以及步骤的执行顺序清晰,某些步骤依赖具体环境,这些步骤仅在父类声明,实现推迟到子类。
模板方法(Template Method)的角色:
抽象类(Abstract Class):由一个模板方法和若干个基本方法构成。
模板方法定义算法骨架,基本方法实现算法各个步骤,是模板方法的组成部分。基本方法又可以分为三种:抽象方法(Abstract Method) 、具体方法(Concrete Method) 、钩子方法(Hook Method) 。
- 具体子类(Concrete Class):继承抽象类并实现抽象方法和钩子方法。
模板方法模式提高代码复用性,实现了反向控制。
适用场景:算法清晰,部分步骤易变;父类部分操作依赖于子类判断。
实现方式
// 抽象父类
public abstract class AbstractCook {
/**
* 模板方法
* 算法步骤固定,使用final修饰,不允许改变
*/
public final void cook() {
// 1.放蔬菜
addVegetable();
// 2.放调料
addDressing();
// 3.翻炒
stirFry();
}
public void addVegetable() {}
// 抽象方法
public abstract void addDressing();
public void stirFry() {}
}
// 具体子类
public class TomatoCook extends AbstractCook {
@Override
public void addVegetable() {
System.out.println("tomato");
}
@Override
public void addDressing() {
System.out.println("salt");
}
}
// 使用者
TomatoCook ck = new TomatoCook();
ck.cook();
源码寻迹
InputStream 类的无参 read() 方法是抽象的,由子类实现,有参 read() 方法通过无参 read() 方法实现。
public abstract class InputStream{
// read()推迟到子类实现
public abstract int read();
// 模板方法
public int read(byte b[], int off, int len){
Objects.checkFromIndexSize(off, len, b.length);
if (len == 0) {
return 0;
}
// this↓
int c = read();
if (c == -1) {
return -1;
}
b[off] = (byte)c;
int i = 1;
try {
for (; i < len ; i++) {
// this↓
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
} catch (IOException ee) {
}
return i;
}
}
策略模式
多种可相互替代的策略/算法。
策略模式(Strategy)的角色:
- 抽象策略类(Strategy):给出所有具体策略类所需的接口。
- 具体策略类(Concrete Strategy):实现抽象策略,提供具体的算法实现。
- 环境类(Context):持有策略类的引用,供使用者调用。
策略模式避免使用多重条件选择语句,策略类之间可以自由切换,可结合享元模式减少策略类的创建。
适用场景:存在多个可相互独立、相互替换的算法。
实现方式
// 抽象策略
public interface Strategy {
void show();
}
// 具体策略
public class SA implements Strategy {
@Override
public void show() {
System.out.println("A");
}
}
public class SB implements Strategy {
@Override
public void show() {
System.out.println("B");
}
}
// 环境
public class Context {
// 持有策略类
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
// 调用具体策略算法
public void show() {
strategy.show();
}
}
// 使用者
Context context = new Context(new Strategy());
context.show();
源码寻迹
Arrays 是环境类,其 sort() 方法可根据传入的策略进行排序操作。
public class Arrays {
public static <T> void sort(T[] a, Comparator<? super T> c) {
if (c == null) {
sort(a);
} else {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, c);
else
TimSort.sort(a, 0, a.length, c, null, 0, 0);
}
}
}
命令模式
将请求封装为命令对象,发起请求方与执行请求方通过命令对象沟通。
命令模式(Command)的角色
- 抽象命令类(Command):声明执行方法。
- 具体命令(Concrete Command):实现命令接口,通常持有接收者,并调用接收者来完成命令。
- 接收者(Receiver): 执行命令。
- 请求者(Invoker):命令对象执行请求,通常持有命令对象,使用命令对象的入口。
请求者持有命令,命令持有接收者。
命令模式将调用操作的对象与实现该操作的对象解耦,可以实现宏命令,方便实现 Undo 和 Redo 操作。
适用场景:调用者和接收者解耦,不直接交互;支持命令的撤销(Undo)操作和恢复(Redo)操作。
实现方式
// 接收者
public class Chef {
public void cook(String name) {
System.out.println("cook " + name);
}
}
// 抽象命令
public interface Command {
void execute();
}
// 具体命令
public class OrderCommand implements Command {
// 持有接收者
private Chef chef;
// 持有订单
private Order order;
public OrderCommand(Chef chef, Order order) {
this.chef = chef;
this.order = order;
}
@Override
public void execute() {
order.getNameList().forEach(name-> chef.cook(name));
}
}
// 订单
public class Order {
// 订单中的菜品
private List<String> nameList;
}
// 请求者
public class Waiter {
// 持有命令
private List<Command> commandList = new ArrayList<>();
public void addCommand(Command cmd) {
commandList.add(cmd);
}
// 发起请求
public void order() {
commandList.forEach(Command::execute);
}
}
// 使用者
Chef cf = new Chef();
Command cmd = new OrderCommand(cf, new Order());
Waiter wt = new Waiter();
wt.addCommand(cmd);
wt.order();
源码寻迹
Runnable 作为抽象命令,Thread 作为请求者。
// 抽象命令
public interface Runnable {
public abstract void run();
}
// 通常将接收者的操作写到run()方法中
// 请求者
public class Thread implements Runnable {
// 持有命令
private Runnable target;
// 发起请求
public synchronized void start(){}
}
责任链模式
职责链模式,一个请求需要多个处理者中的一个处理者处理,将多个处理者链接起来,将请求沿链传递,直到处理完毕。
职责链模式(Chain of Responsibility)的角色:
- 抽象处理者(Handler):包含抽象处理方法和一个后继连接。
- 具体处理者(Concrete Handler):实现抽象处理者,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
责任链模式降低了请求发送者和接收者/处理者的耦合度,明确了各处理者的职责,便于工作流程的拓展。责任链的建立依靠使用者,增加了使用的复杂性。
实现方式
// 抽象处理者
public abstract class Handler {
// 处理范围界限
protected final static int LEVEL_FIRST = 1;
protected final static int LEVEL_SECOND = 5;
// 可处理的范围
private int levelFrom;
private int levelTo;
// 后继者
private Handler nextHandler;
public Handler(int levelFrom, int levelTo) {
this.levelFrom = levelFrom;
this.levelTo = levelTo;
}
// 处理请求
public final void handle(Request req) {
// 当前处理器处理请求
doHandle(req);
// 检查是否需要交由后继处理器处理
if (nextHandler != null && req.getLevel() >= levelTo)
nextHandler.handle(req);
}
// 处理请求
protected abstract void doHandle(Request req);
}
// 具体处理者
public class FirstHandler extends Handler {
public FirstHandler() {
super(0, Handler.LEVEL_FIRST);
}
@Override
protected void doHandle(Request req) {}
}
public class SecondHandler extends Handler {
public SecondHandler() {
super(Handler.LEVEL_FIRST, Handler.LEVEL_SECOND);
}
@Override
protected void doHandle(Request req) {}
}
public class ThirdHandler extends Handler {
public ThirdHandler() {
super(Handler.LEVEL_SECOND, Integer.MAX_VALUE);
}
@Override
protected void doHandle(Request req) {}
}
// 使用者
// 创建责任链
FirstHandler h1 = new FirstHandler();
SecondHandler h2 = new SecondHandler();
ThirdHandler h3 = new ThirdHandler();
h1.setNextHandler(h2);
h2.setNextHandler(h3);
// 处理请求
Request req = new Request(4);
h1.handle(req);
源码寻迹
JavaWeb 中的 FilterChain 通过责任链模式过滤请求。
public interface Filter {
void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain){}
}
public interface FilterChain {
void doFilter(ServletRequest req, ServletResponse resp);
}
状态模式
对于有状态的对象,把复杂的判断逻辑封装到状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
状态模式(State)的角色
- 环境(Context):上下文,维护当前状态,将当前状态相关操作委托给当前状态对象处理。
- 抽象状态(State):定义行为接口。
- 具体状态(Concrete State):实现抽象状态。
状态模式将状态转换逻辑封装到状态对象中,避免了巨大的条件语句块,可以方便地增加新的状态。
状态模式的使用会导致类的个数增加,并且不符合开闭原则。
实现方式
public class Context {
public final static int LIMIT = 0;
// 若val≤LIMIT,则状态为LowState,否则为HighState
private int val;
// 状态对象常量
protected final HighState HIGH_STATE = new HighState(this);
protected final LowState LOW_STATE = new LowState(this);
// 持有状态
private State state;
public Context(int val) {
this.val = val;
this.state = (val > LIMIT) ? HIGH_STATE : LOW_STATE;
}
// 具体操作交由当前状态对象实现
public void plus(int v) {
this.state.plus(v);
}
public void sub(int v) {
this.state.sub(v);
}
}
// 抽象状态
public abstract class State {
// 持有环境
protected Context context;
// +v
public abstract void plus(int v);
// -v
public abstract void sub(int v);
}
// 具体状态
public class HighState extends State {
@Override
public void plus(int v) {
this.context.setVal(
this.context.getVal() + v
);
}
@Override
public void sub(int v) {
this.context.setVal(
this.context.getVal() - v
);
if (this.context.getVal() <= Context.LIMIT)
this.context.setState(this.context.LOW_STATE);
}
}
// 具体状态
public class LowState extends State {
@Override
public void plus(int v) {
this.context.setVal(
this.context.getVal() + v
);
if (this.context.getVal() > Context.LIMIT)
this.context.setState(this.context.HIGH_STATE);
}
@Override
public void sub(int v) {
this.context.setVal(
this.context.getVal() - v
);
}
}
// 使用者
Context context = new Context(1024);
conetxt.sub(12);
观察者模式
发布订阅模式,多个观察者监听同一主题,主题发生变化时,通知所有观察者。
观察者模式(Observer)的角色
- 抽象主题(Subject):抽象被观察者,持有所有观察者对象。
- 具体主题(Concrete Subject):实现抽象主题。
- 抽象观察者(Observer):定义接收通知的接口。
- 具体观察者(Concrete Observer):实现抽象观察者。
观察者模式可实现广播机制,观察者较多时发送通知较为耗时。
适用场景:当一个对象的状态发生改变需要通知多个对象。
实现方式
// 抽象观察者
public interface Observer {
// 接收通知的方法
void update(String msg);
}
// 具体观察者
public class ConcreteObserver implements Observer {
@Override
public void update(String msg) {}
}
// 抽象主题
public interface Subject {
// 添加观察者
void add(Observer observer);
// 移除观察者
void remove(Observer observer);
// 通知观察者
void notify(String msg);
}
// 具体主题
public class ConcreteSubject implements Subject {
// 存放所有观察者
private final List<Observer> observerList = new ArrayList();
@Override
public void add(Observer observer) {
observerList.add(observer);
}
@Override
public void remove(Observer observer) {
observerList.remove(observer);
}
@Override
public void notify(String msg) {
observerList.forEach(it -> it.update(msg));
}
}
// 使用者
ConcreteSubject sub = new ConcreteSubject();
sub.add(new ConcreteObserver());
sub.add(new ConcreteObserver());
sub.notify();
源码寻迹
java.util.Observable 作为抽象主题,java.util.Observer 作为抽象观察者。
// 抽象主题
@Deprecated(since="9")
public class Observable {
private Vector<Observer> obs;
}
// 抽象观察者
@Deprecated(since="9")
public interface Observer {
void update(Observable o, Object arg);
}
中介者模式
多个同类相互关联时,关系成网状结构,通过中介者将网状结构转为星型结构。
若 A 和 B 需要交互,则 A 和 B 不直接相互调用,而是通过中介者沟通。
中介者模式(Mediator)的角色
- 抽象中介者(Mediator):提供同时对象注册于转发同事对象信息的抽象方法。
- 具体中介者(Concrete Mediator):抽象中介者。
- 抽象同事类(Colleague):持有中介者对象,实现影响同事类的公共方法。
- 具体同事类(Concrete Colleague):实现抽象同事类。
中介者模式将同事之间的交互封装到中介者,实现同事松耦合和集中控制。
同事过多会导致中介者复杂而庞大,难以维护。
适用场景:对象存在复杂的引用关系。
实现方式
// 抽象中介者
public interface Mediator {
// 消息
int CALL_A_TO_SING = 0;
int CALL_A_TO_JUMP = 1;
int CALL_B_TO_RAP = 2;
int CALL_B_TO_BASKETBALL = 3;
/**
* 将具体同事对象注册到中介者中
*
* @param name 具体同事对象名称
* @param colleague 具体同事对象
*/
void register(String name, Colleague colleague);
/**
* 接受具体同事对象发送过来的消息并进行处理
* 核心方法,中介者通过getMsg()方法协调各同事完成任务
*
* @param name 具体同事对象名称
* @param msg 消息
*/
void getMsg(String name, int msg);
}
// 具体中介者
public class ConcreteMediator implements Mediator {
// 存放具体同事
private Map<String, Colleague> cMap = new HashMap<>();
// 类到名称的映射
private Map<Class<?>, String> nameMap = new HashMap<>();
@Override
public void register(String name, Colleague colleague) {
cMap.put(name, colleague);
nameMap.put(colleague.getClass(), name);
}
@Override
public void getMsg(String name, int msg) {
// 发送消息的对象
Colleague colleague = cMap.get(name);
// 协调任务
if (colleague instanceof AColleague) {
switch (msg) {
case CALL_B_TO_RAP -> {
((BColleague) cMap.get(
nameMap.get(BColleague.class)
)).rap();
}
default -> throw new Exception();
}
} else if (colleague instanceof BColleague) {
switch (msg) {
case CALL_A_TO_JUMP -> {
((AColleague) cMap.get(
nameMap.get(AColleague.class)
)).jump();
}
default -> throw new Exception();
}
}
}
}
// 抽象同事类
public abstract class Colleague {
// 持有中介者
protected Mediator mediator;
// 名称
protected String name;
public Colleague(Mediator mediator, String name) {
this.mediator = mediator;
this.name = name;
}
// 发送消息给中介者
public abstract void sendMsg(int msg);
}
// 具体同事类
public class AColleague extends Colleague {
public AColleague(Mediator mediator, String name) {
super(mediator, name);
// 在中介者中注册当前具体同事类
mediator.register(name, this);
}
@Override
public void sendMsg(int msg) {
this.mediator.getMsg(name, msg);
}
// A完成某项任务的操作
public void jump() {}
}
// 具体同事类
public class BColleague extends Colleague {
public BColleague(Mediator mediator, String name) {
super(mediator, name);
// 在中介者中注册当前具体同事类
mediator.register(name, this);
}
@Override
public void sendMsg(int msg) {
this.mediator.getMsg(name, msg);
}
// B完成某项任务的操作
public void rap() {
// 完成任务后仍可发送消息给中介者,让其他同事完成任务
sendMsg(Mediator.CALL_A_TO_JUMP);
}
}
// 使用者
Mediator mediator = new ConcreteMediator();
Colleague ca = new AColleague(mediator,"ca");
Colleague cb = new BColleague(mediator,"cb");
ca.sendMsg(Mediator.CALL_B_TO_RAP);
注意,上述代码中,将消息到目标对象(执行任务的对象)的映射简化为了类到目标对象的映射,所以只支持每个类存在单个对象,若需支持多个对象,只需修改消息到目标对象的映射即可。
迭代器模式
提供对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。
迭代器模式(Iterator)的角色
- 抽象聚合(Aggregate):定义操作迭代器的接口。
- 具体聚合(Concrete Aggregate):实现抽象聚合。
- 抽象迭代器(Iterator):定义遍历访问聚合对象的接口。
- 具体迭代器(Concrete Iterator):实现抽象迭代器。
迭代器模式支持以多种方式遍历元素,简化了聚合类的设计,隐藏了聚合类的实现。
适用场景:需要以多种方式遍历元素;隐藏聚合对象的内部细节。
实现方式
// 抽象迭代器
public interface Iterator<T> {
boolean hasNext();
T next();
}
// 具体迭代器
public class CollectionIterator<T> implements Iterator<T> {
// 元素集合
private List<T> list;
// 记录遍历位置
private int pos = 0;
public CollectionIterator(List<T> list) {
this.list = list;
}
@Override
public boolean hasNext() {
return pos + 1 < list.size();
}
@Override
public T next() {
if (!hasNext()) return null;
return list.get(pos++);
}
}
// 抽象聚合
public interface Collection<T> {
// 添加元素
void add(T t);
// 删除元素
void remove(T t);
// 获取迭代器
CollectionIterator<T> getIterator();
}
// 具体聚合
public class ListCollection<T> implements Collection<T> {
private List<T> list = new ArrayList<>();
@Override
public void add(T t) {
list.add(t);
}
@Override
public void remove(T t) {
list.remove(t);
}
@Override
public CollectionIterator<T> getIterator() {
return new CollectionIterator<>(list);
}
}
// 使用者
Collection<String> col = new ListCollection();
Iterator<String> it = col.getIterator();
while(it.hasNest()){
System.out.println(it.next());
}
源码寻迹
List 作为抽象聚合,ArrayList 作为具体聚合,Iterator 作为抽象迭代器,Itr 作为具体迭代器。
// 抽象聚合
public interface List<E> {
// 抽象迭代器
Iterator<E> iterator();
}
// 具体聚合
public class ArrayList<E> implements List<E>{
public Iterator<E> iterator() {
// 具体迭代器
return new Itr();
}
}
访问者模式
在不改变数据结构的前提下,封装对数据结构中元素的新的操作。
访问者模式(Visitor)的角色
- 抽象访问者(Visitor):定义访问元素的接口,参数为元素。
- 具体访问者(Concrete Vistor):实现抽象访问者。
- 抽象元素(Element):定义接受访问者的接口。
- 具体元素(Concrete Element):实现抽象元素。
- 对象结构(Object Structure):含有一组元素,提供迭代元素的方法。
访问者模式在不修改对象结构中的元素的前提下,可以为元素添加新的功能;通过访问者来分离无关的行为,把相关的行为封装在同一个访问者,每个访问者的功能单一。
增加元素需要修改访问者,违背开闭原则;抽象访问者依赖具体元素,违反依赖倒置原则。
适用场景:
- 对象(Cat)结构稳定,算法操作(handle)经常变化。
- 需要对对象提供多种不同的操作,且要避免这些操作影响对象结构。
实现方式
// 抽象元素
public interface Animal {
// 接受访问者访问
void accept(Person person);
}
// 具体元素
public class Cat implements Animal {
@Override
public void accept(Person person) {
person.handle(this);
}
}
public class Dog implements Animal {
@Override
public void accept(Person person) {
person.handle(this);
}
}
// 抽象访问者
public interface Person {
void handle(Cat cat);
void handle(Dog dog);
}
// 具体访问者
public class Feeder implements Person {
@Override
public void handle(Cat cat) { }
@Override
public void handle(Dog dog) { }
}
// 对象结构
public class Home {
// 存储元素
private List<Animal> animalList = new ArrayList<>();
// 添加元素
public void add(Animal animal) {
animalList.add(animal);
}
// 访问元素
public void action(Person person) {
animalList.forEach(animal -> animal.accept(person));
}
}
// 使用者
Home home = new Home();
home.add(new Cat());
home.add(new Dog());
home.action(new Feeder());
拓展-双分派
分派:根据对象类型而对方法进行选择。
- 静态分派:发生在编译时期,分派根据静态类型发生,如方法重载。
- 动态分派:发生在运行时期,分派根据实际类型发生,如方法重写。
public class Animal {
void accept(Person person){
person.handle(this);
};
}
public class Cat extends Animal {
@Override
public void accept(Person person) {
person.handle(this);
}
}
public class Dog extends Animal {
@Override
public void accept(Person person) {
person.handle(this);
}
}
public class Person {
void handle(Animal animal){}
void handle(Cat animal){}
void handle(Dog animal){}
}
Animal animal = new Cat();
animal.accept(person);
对于上面这段代码,accept() 是 Cat 重写父类/接口的方法,故是动态分派,根据实际类型分派,也即实际调用 Cat 的accept() 方法。
public class Cat implements Animal {
@Override
public void accept(Person person) {
person.handle(this);
}
}
handle() 是重载方法,故是静态分派,根据静态类型分派,this 的静态类型是 Cat,故执行的是如下方法:
void handle(Cat animal){}
综上,共完成两次分派——双分派。
备忘录模式
快照模式,在不破坏封装性的前提下,捕获对象的内部状态并在对象之外进行保存,以便后续恢复。
备忘录的角色
- 发起人(Originator):记录当前时刻的内部状态,提供创建备忘录和恢复备忘录的方法。
- 备忘录(Memento):负责存储发起人的内部状态。
- 管理者(Caretaker):对备忘录进行管理,提供保存与获取备忘录的功能。
备忘录模式提供一种恢复状态的机制,实现了对内部状态的封装,历史状态的管理交由管理者管理,符合单一职责原则。当历史状态过多时,资源消耗大。
适用场景:存档;回滚。
白箱备忘录
备忘录角色对任何对象都提供一个接口,即宽接口,备忘录的内部所存储的状态对所有对象公开。
// 发起人
public class Originator {
private int val;
// 初始化内部状态
public void initState() {
this.val = 100;
}
// 修改内部状态
public void change() {
this.val = 99;
}
// 保存内部状态
public Memento saveState() {
return new Memento(val);
}
// 恢复内部状态
public void recoverState(Memento memento) {
this.val = memento.getVal();
}
}
// 备忘录
public class Memento {
private int val;
}
// 管理者
public class Caretaker {
// 备忘录
private Memento memento;
}
// 使用者
Originator ogn = new Originator();
ogn.initState();
Caretaker ctk = new Caretaker();
ctk.setMemento(ogn.saveState());
ogn.change();
ogn.recoverState(ctk.getMemento());
黑箱备忘录
备忘录对发起人提供宽接口,为其他对象提供窄接口,方式是将备忘录设计成发起人的成员内部类。
// 发起人
public class Originator {
private int val;
// 初始化内部状态
public void initState() {
this.val = 100;
}
// 修改内部状态
public void change() {
this.val = 99;
}
// 保存内部状态
public Memento saveState() {
return new InternalMemento(val);
}
// 恢复内部状态
public void recoverState(Memento memento) {
this.val = ((InternalMemento) memento).getVal();
}
// 备忘录
private static class InternalMemento implements Memento {
private int val;
}
}
// 备忘录接口
public interface Memento {
}
// 管理者
public class Caretaker {
// 备忘录
private Memento memento;
}
解释器模式
定义文法,解释器根据文法解析句子。
解释器模式的角色
- 抽象表达式(Abstract Expression):定义解释方法 interpret()。
- 终结符表达式(Terminal Expression)
- 非终结符表达式(Nonterminal Expression)
- 环境(Context):传递共享数据。
解释器模式易于改变和拓展文法,但复杂文法难以维护,执行效率低。
适用场景:文法简单,问题可用语言表示,句子可表示为抽象语法树。
实现方式
// 抽象表达式
public abstract class AbstractExpression {
// 解释表达式
public abstract int interpret(Context context);
}
// 变量
public class Variable extends AbstractExpression {
@Override
public int interpret(Context context) {
return context.get(this);
}
}
// 加法表达式
public class Plus extends AbstractExpression {
private AbstractExpression left;
private AbstractExpression right;
@Override
public int interpret(Context context) {
return left.interpret(context) + right.interpret(context);
}
}
// 减法表达式
public class Sub extends AbstractExpression {
private AbstractExpression left;
private AbstractExpression right;
@Override
public int interpret(Context context) {
return left.interpret(context) - right.interpret(context);
}
}
// 环境
public class Context {
// 存储变量值
private Map<Variable, Integer> map = new HashMap<>();
// 获取变量值
public int get(Variable var) {
return map.get(var);
}
// 设置变量值
public void assign(Variable var, int val) {
map.put(var, val);
}
}
// 使用者
Context context = new Context();
Variable v1 = new Variable();
context.assign(v1, 1);
Variable v2 = new Variable();
context.assign(v2, 2);
Variable v3 = new Variable();
context.assign(v3, 1);
AbstractExpression exp = new Plus(v1, new Sub(v2, v3));
END
文章文档:公众号 字节幺零二四
回复关键字可获取本文文档。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。