设计模式专题之 —— 行为类模式

行为类模式包括责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式、访问者模式。

一、模板方法模式(Template Method Pattern)

1.1 定义

***Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure. ***
定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

1.2 通用代码

抽象模板类
package designpattern.template;

public abstract class AbstractClass {
	//基本方法
	protected abstract void doSomething();
	//基本方法
	protected abstract void doAnything();
	//模板方法
	public void templateMethod() {
		/*
		 * 调用基本方法,完成相关的逻辑
		 */
		this.doAnything();
		this.doSomething();
	}
}
具体模板类
package designpattern.template;

public class ConcreteClass1 extends AbstractClass {

	//实现基本方法
	@Override
	protected void doSomething() {
		//业务逻辑处理
		System.out.println("class1 do something");
	}

	@Override
	protected void doAnything() {
		//业务逻辑处理
		System.out.println("class1 do anything");
	}
}

package designpattern.template;

public class ConcreteClass2 extends AbstractClass {

	//实现基本方法
	@Override
	protected void doSomething() {
		//业务逻辑处理
		System.out.println("class2 do something");
	}

	@Override
	protected void doAnything() {
		//业务逻辑处理
		System.out.println("class2 do anything");
	}
}
场景类
package designpattern.template;

public class Client {
	public static void main(String[] args) {
		AbstractClass class1 = new ConcreteClass1();
		AbstractClass class2 = new ConcreteClass2();

		//调用模板方法
		class1.templateMethod();
		class2.templateMethod();
	}
}

1.3 应用

优点
  • 封装不变部分,扩展可变部分
  • 提取公共部分代码,便于维护
  • 行为由父类控制,子类实现
缺点

按照设计习惯,抽象类负责声明最抽象、最一般的事物属性和方法,实现类完成具体的事物属性和方法。但是模板方法模式却颠倒了,抽象类定义了部分抽象方法,由子类实现,子类执行的结果影响了父类的结果,也就是子类对父类产生了影响,这在复杂的项目中,会带来代码阅读的难度。

使用场景
  • 多个子类有公有的方法,并且逻辑基本相同时
  • 重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现
  • 重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数约束其行为

二、中介者模式(Mediator Pattern)

2.1 定义

Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
用一个中介对象封装一系列的对象交互,中介者使各对象不需要显式地相互作用,从而使其耦合松散,而且可以独立地改变他们之间的交互。

2.2 通用代码

通用抽象中介者
package designpattern.mediator;

public abstract class Mediator {
	//定义同事类
	protected ConcreteColleague1 c1;
	protected ConcreteColleague2 c2;
	//通过getter/setter方法把同事类注入进来
	public ConcreteColleague1 getC1() {
		return c1;
	}
	
	public void setC1(ConcreteColleague1 c1) {
		this.c1 = c1;
	}

	public ConcreteColleague2 getC2() {
		return c2;
	}

	public void setC1(ConcreteColleague2 c2) {
		this.c2 = c2;
	}
	
	//中介者模式的业务逻辑
	public abstract void doSomething1();
	public abstract void doSomething2();
}
通用中介者
package designpattern.mediator;

public class ConcreteMediator extends Mediator {
	@Override
	public void doSomething1() {
		//调用同事类的方法,只要是public方法都可以调用
		super.c1.selfMethod1();
		super.c2.depMethod2();
	}

	@Override
	public void doSomething2() {
		super.c1.depMethod1();
		super.c2.selfMethod2();
	}
}
抽象同事类
package designpattern.mediator;

public abstract class Colleague {

	protected Mediator mediator;

	public Colleague(Mediator _mediator) {
		this.mediator = _mediator;
	}
}

具体同事类
package designpattern.mediator;

public class ConcreteColleague1 extends Colleague {

	//通过构造函数传递传递中介者
	public ConcreteColleague1(Mediator _mediator) {
		super(_mediator);
	}

	//自有方法 self-method
	public void selfMethod1() {
		//处理自己的业务逻辑
		System.out.println("1 处理自己的业务逻辑 自有方法");
	}

	//依赖方法 dep-method
	public void depMethod1() {
		//处理自己的业务逻辑
		System.out.println("1 处理自己的业务逻辑 依赖方法");
		//自己不能处理的业务逻辑,委托给中介者处理
		super.mediator.doSomething1();
	}
}

package designpattern.mediator;

public class ConcreteColleague2 extends Colleague {

	//通过构造函数传递传递中介者
	public ConcreteColleague2(Mediator _mediator) {
		super(_mediator);
	}

	//自有方法 self-method
	public void selfMethod2() {
		//处理自己的业务逻辑
		System.out.println("2 处理自己的业务逻辑 自有方法");
	}

	//依赖方法 dep-method
	public void depMethod2() {
		//处理自己的业务逻辑
		System.out.println("2 处理自己的业务逻辑 依赖方法");
		//自己不能处理的业务逻辑,委托给中介者处理
		super.mediator.doSomething2();
	}
}

2.3 应用

优点

减少了类间的依赖,把原有的一对多的依赖变成了一对一的依赖,同事类只依赖中介者,减少了依赖,当然同时也降低了类间的耦合。

缺点

中介者会膨胀得很大,而且逻辑复杂,原本N个对象直接的相互依赖关系转换为中介者和同事类的依赖关系,同事类越多,中介者的逻辑就越复杂。

使用场景

中介者模式适用于多个对象之间紧密耦合的情况。

三、责任链模式(Chain-of-responsibility Pattern)

3.1 定义

Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

3.2 通用代码

抽象处理者
package designpattern.chainofresponsibility;

public abstract class Handler {
	private Handler nextHandler;
	//每个处理者都必须对请求做出处理
	public final Response handleMessage(Request request) {
		Response response = null;
		//判断是否是自己的处理级别
		if (this.getHandlerLevel().equals(request.getRequestLevel())) {
			response = this.echo(request);
		} else {    // 不属于自己的处理级别
			// 判断是否有下一个处理者
			if (this.nextHandler != null) {
				response = this.nextHandler.handleMessage(request);
			} else {
				//没有适当的处理者,业务自行处理
			}
		}
		return response;
	}

	//设置下一个处理者是谁
	public void setNext(Handler _handler) {
		this.nextHandler = _handler;
	}

	//每个处理者都有一个处理级别
	protected  abstract Level getHandlerLevel();

	//每个处理者都必须实现处理任务
	protected abstract Response echo(Request request);
}
具体处理者
package designpattern.chainofresponsibility;

public class ConcreteHandler1 extends Handler {

	//定义自己的处理逻辑
	@Override
	protected Level getHandlerLevel() {
		//完成处理逻辑
		System.out.println("get level of handler 1");
		return null;
	}

	//设置自己的处理级别
	@Override
	protected Response echo(Request request) {
		//设置自己的处理级别
		System.out.println("set level of handler 1");
		return null;
	}
}

package designpattern.chainofresponsibility;

public class ConcreteHandler2 extends Handler {

	//定义自己的处理逻辑
	@Override
	protected Level getHandlerLevel() {
		//完成处理逻辑
		System.out.println("get level of handler 2");
		return null;
	}

	//设置自己的处理级别
	@Override
	protected Response echo(Request request) {
		//设置自己的处理级别
		System.out.println("set level of handler 2");
		return null;
	}
}
package designpattern.chainofresponsibility;

public class ConcreteHandler3 extends Handler {

	//定义自己的处理逻辑
	@Override
	protected Level getHandlerLevel() {
		//完成处理逻辑
		System.out.println("get level of handler 3");
		return null;
	}

	//设置自己的处理级别
	@Override
	protected Response echo(Request request) {
		//设置自己的处理级别
		System.out.println("set level of handler 3");
		return null;
	}
}
模式中有关框架代码
package designpattern.chainofresponsibility;

public class Level {
	//定义一个请求和处理等级
}
package designpattern.chainofresponsibility;


public class Request {
	//请求的等级
	public Level getRequestLevel() {
		return null;
	}
}

package designpattern.chainofresponsibility;

public class Response {
	//处理者返回的数据
}

场景类
package designpattern.chainofresponsibility;

public class Client {
	public static void main(String[] args) {
		//声明所有的处理节点
		Handler handler1 = new ConcreteHandler1();
		Handler handler2 = new ConcreteHandler2();
		Handler handler3 = new ConcreteHandler3();
		//设置链中的阶段顺序 1 --> 2 --> 3
		handler1.setNext(handler2);
		handler2.setNext(handler3);
		//提交请求,返回结果
		Response response = handler1.handleMessage(new Request());
		System.out.println(response);
	}
}

3.3 应用

优点

将请求和处理分开

缺点
  • 性能问题
  • 调试流程复杂
注意事项

链中节点数量需要控制,避免出现超长链的情况,一般的做法是在Handler中设置一个最大节点数量,在setNext 方法中判断是否已经超过其阈值,超过则不允许该链建立,避免无意识地破坏系统性能。

四、策略模式(Strategy Pattern)

4.1 定义

策略模式是一种比较简单的模式,也叫作政策模式(Policy Pattern)。
Define a family of algorithms, encapsulate each one, and make them interchangeable.
定义一组算法,将每个算法都封装起来,并且使他们之间可以互换。

4.2 通用代码

抽象策略角色
package designpattern.strategy;

public interface Strategy {
	//策略模式的运算法则
	public void doSomething();
}
具体策略角色
package designpattern.strategy;

public class ConcreteStrategy1 implements Strategy {
	@Override
	public void doSomething() {
		System.out.println("具体策略1的运算法则");
	}
}
package designpattern.strategy;

public class ConcreteStrategy2 implements Strategy {
	@Override
	public void doSomething() {
		System.out.println("具体策略2的运算法则");
	}
}

封装角色
package designpattern.strategy;

public class Context {
	//抽象策略
	private Strategy strategy;
	//构造函数设置具体策略
	public Context(Strategy _strategy) {
		this.strategy = _strategy;
	}
	//封装后的策略方法
	public void doAnything() {
		this.strategy.doSomething();
	}
}

高层模块
package designpattern.strategy;

public class Client {
	public static void main(String[] args) {
		//声明一个具体的策略
		Strategy strategy = new ConcreteStrategy1();
		//声明上下文对象
		Context context = new Context(strategy);
		//执行封装后的方法
		context.doAnything();

		strategy = new ConcreteStrategy2();
		context = new Context(strategy);
		context.doAnything();
	}
}

4.3 应用

优点
  • 算法可以自由切换
  • 避免使用多重条件判断
  • 扩展性良好
缺点
  • 策略类数量增多
  • 所有的策略类都需要对外暴露
注意事项
  • 多个类只有在算法或行为上稍有不同的场景
  • 算法需要自由切换的场景
  • 需要屏蔽算法规则的场景

4.4 策略枚举

五、迭代器模式(IteratorPattern)

5.1 定义

策略模式是一种比较简单的模式,也叫作政策模式(Policy Pattern)。
Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
它提供一种方法访问一个容器对象中的各个元素,而又不需要暴露该对象的内部细节。

5.2 通用代码

抽象迭代器
package designpattern.iterator;

public interface Iterator {
	//遍历到下一个元素
	public Object next();
	//是否已经遍历到尾部
	public boolean hasNext();
	//删除当前指向的元素
	public boolean remove();
}

具体迭代器
package designpattern.iterator;

import java.util.Vector;

public class ConcreteIterator implements Iterator {

	private Vector<Object> vector;
	private int cursor = 0;


	public ConcreteIterator(Vector<Object> _vector) {
		this.vector = _vector;
	}
	@Override
	public Object next() {
		Object result = null;
		if (this.hasNext()) {
			result = this.vector.get(this.cursor++);
		}
		return result;
	}

	@Override
	public boolean hasNext() {
		return !(this.cursor == this.vector.size());
	}

	@Override
	public boolean remove() {
		this.vector.remove(this.cursor);
		return true;
	}
}
抽象容器
package designpattern.iterator;

public interface Aggregate {

	public void add(Object object);

	public void remove(Object object);

	public Iterator iterator();
}

具体容器
package designpattern.iterator;

import java.util.Vector;

public class ConcreteAggregate implements Aggregate {

	private Vector<Object> vector = new Vector<>();

	@Override
	public void add(Object object) {
		this.vector.add(object);
	}

	@Override
	public void remove(Object object) {
		this.vector.remove(object);
	}

	@Override
	public Iterator iterator() {
		return new ConcreteIterator(this.vector);
	}
}

场景类
package designpattern.iterator;

public class Client {
	public static void main(String[] args) {

		Aggregate agg = new ConcreteAggregate();
		agg.add("abc");
		agg.add("aaa");
		agg.add("1234");

		Iterator iterator = agg.iterator();
		while (iterator.hasNext()) {
			System.out.println(iterator.next());
		}
	}
}

5.3 应用

为容器服务
java.util.Iterable 接口
Java 已经把迭代器模式融入到基本API中了

六、观察者模式(ObserverPattern)

6.1 定义

观察者模式也叫发布订阅模式(Publish/subscribe),它是一个在项目中经常使用的模式。
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。

6.2 通用代码

被观察者
package designpattern.observer;

import java.util.Vector;

public abstract class Subject {

	private Vector<Observer> observers = new Vector<>();

	public void addObserver(Observer o) {
		this.observers.add(o);
	}

	public void delObserver(Observer o) {
		this.observers.remove(o);
	}

	public void notifyObservers() {
		this.observers.forEach(Observer::update);
	}

}
具体被观察者
package designpattern.observer;

public class ConcreteSubject extends Subject {

	public void doSomething() {
		/*
		 * do something
		 */
		super.notifyObservers();
	}
}
观察者
package designpattern.observer;

public interface Observer {
	//更新方法
	public void update();
}

具体观察者
package designpattern.observer;

public class ConcreteObserver implements Observer {
	//实现更新方法
	@Override
	public void update() {
		System.out.println("接收到信息,并进行处理!");
	}
}
场景类
package designpattern.observer;

public class Client {
	public static void main(String[] args) {
		ConcreteSubject subject = new ConcreteSubject();
		Observer obs = new ConcreteObserver();
		subject.addObserver(obs);
		subject.doSomething();
	}
}

6.3 应用

优点
  • 观察者和被观察者之间是抽象耦合
  • 建立一套触发机制
缺点
  • 开发效率和运行效率
使用场景
  • 关联行为场景。需要注意的是,关联行为是可拆分的,而不是“组合”关系
  • 事件多级触发场景
  • 跨系统的消息交换场景,如消息队列的处理机制
注意事项
  • 广播链问题
  • 异步处理问题

七、备忘录模式(MementoPattern)

7.1 定义

Without violating encapsulation, capture and externalize an objects’s internal state so that the object can be restored to this state later.
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。

7.2 通用代码

发起人角色
package designpattern.memento;

public class Originator {

	private String state = "";

	public String getState() {
		return state;
	}

	public void setState(String state) {
		this.state = state;
	}

	public Memento createMemento() {
		return new Memento(this.state);
	}

	public void restoreMemento(Memento _memento) {
		this.setState(_memento.getState());
	}
}

备忘录角色
package designpattern.memento;

public class Memento {

	private String state;

	public Memento(String _state) {
		this.state = _state;
	}

	public String getState() {
		return state;
	}

	public void setState(String state) {
		this.state = state;
	}
}

备忘录管理员角色
package designpattern.memento;

public class Caretaker {
	private Memento memento;

	public Memento getMemento() {
		return memento;
	}

	public void setMemento(Memento memento) {
		this.memento = memento;
	}
}

场景类
package designpattern.memento;

public class Client {
	public static void main(String[] args) {
		Originator originator = new Originator();
		Caretaker caretaker = new Caretaker();

		caretaker.setMemento(originator.createMemento());

		originator.restoreMemento(caretaker.getMemento());
	}
}

7.3 应用

使用场景
  • 需要保存和恢复数据的相关状态场景
  • 提供一个可回滚(rollback)的操作
  • 需要监控的副本场景中
  • 数据库连接的事务管理用的就是备忘录模式
注意事项
  • 备忘录的生命周期
  • 备忘录的性能

八、访问者模式(Visitor Pattern)

8.1 定义

Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.
封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

8.2 通用代码

抽象元素
package designpattern.visitor;

public abstract class Element {
	//定义业务逻辑
	public abstract void doSomething();
	//允许谁来访问
	public abstract void accept(IVisitor visitor);
}


具体元素
package designpattern.visitor;

public class ConcreteElement1 extends Element {
	//完善业务处理
	@Override
	public void doSomething() {
		//业务处理
		System.out.println("element 1 业务处理");
	}

	//允许那个访问者访问
	@Override
	public void accept(IVisitor visitor) {
		visitor.visit(this);
	}
}
package designpattern.visitor;

public class ConcreteElement2 extends Element {
	//完善业务处理
	@Override
	public void doSomething() {
		//业务处理
		System.out.println("element 2 业务处理");
	}

	//允许那个访问者访问
	@Override
	public void accept(IVisitor visitor) {
		visitor.visit(this);
	}
}
抽象访问者
package designpattern.visitor;

public interface IVisitor {

	public void visit(ConcreteElement1 el1);

	public void visit(ConcreteElement2 el2);
	
}
具体访问者
package designpattern.visitor;

public class Visitor implements IVisitor {

	//访问el1元素
	@Override
	public void visit(ConcreteElement1 el1) {
		el1.doSomething();
	}

	//访问el2元素
	@Override
	public void visit(ConcreteElement2 el2) {
		el2.doSomething();
	}
}
结构对象
package designpattern.visitor;

import java.util.Random;

public class ObjectStructure {

	//对象生成器,这里通过一个工厂方法模式模拟
	public static Element createElement() {
		Random rand = new Random();
		return rand.nextInt(100) > 50 ? new ConcreteElement1() : new ConcreteElement2();
	}
}
场景类
package designpattern.visitor;

public class Client {
	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
			Element el = ObjectStructure.createElement();
			el.accept(new Visitor());
		}
	}
}

8.3 应用

优点
  • 符合单一职责原则
  • 优秀的扩展性
  • 灵活性非常高
缺点
  • 具体元素对访问者公布细节
  • 具体元素变更比较困难
  • 违背了依赖倒置原则
使用场景
  • 迭代器模式不能胜任的场景
  • 需要对一个对象结构中的对象进行很多不同并且不相关的操作的场景

九、状态模式(State Pattern)

9.1 定义

Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。

9.2 通用代码

抽象环境角色
package designpattern.state;

public abstract class State {

	//定义一个环境角色,提供子类访问
	protected Context context;

	//设置环境角色
	public void setContext(Context _context) {
		this.context = _context;
	}

	//行为1
	public abstract void handle1();

	//行为2
	public abstract void handle2();
}

环境角色
package designpattern.state;

public class ConcreteState1 extends State {
	@Override
	public void handle1() {
		//本状态下必须处理的逻辑
		System.out.println("状态1下必须处理的逻辑");
	}

	@Override
	public void handle2() {
		//设置当前状态为state2
		super.context.setCurrentState(Context.STATE_2);
		//过渡到state2状态,由Context实现
		super.context.handle2();
	}
}

package designpattern.state;

public class ConcreteState2 extends State {
	@Override
	public void handle1() {
		//设置当前状态为state1
		super.context.setCurrentState(Context.STATE_1);
		//过渡到state1状态,由Context实现
		super.context.handle1();

	}

	@Override
	public void handle2() {
		//本状态下必须处理的逻辑
		System.out.println("状态2下必须处理的逻辑");
	}
}

具体环境角色
package designpattern.state;

public class Context {
	//定义状态
	public final static State STATE_1 = new ConcreteState1();
	public final static State STATE_2 = new ConcreteState2();
	//当前状态
	private State currentState;
	//获得当前状态
	public State getCurrentState() {
		return currentState;
	}
	//设置当前状态

	public void setCurrentState(State currentState) {
		this.currentState = currentState;
		//切换状态
		this.currentState.setContext(this);
	}

	//行为委托
	public void handle1() {
		this.currentState.handle1();
	}

	public void handle2() {
		this.currentState.handle2();
	}
}
场景类
package designpattern.state;

public class Client {
	public static void main(String[] args) {
		//定义环境角色
		Context context = new Context();
		//初始化状态
		context.setCurrentState(new ConcreteState1());
		//行为执行
		context.handle1();
		context.handle2();
	}
}

9.3 应用

优点
  • 结构清晰
  • 遵循设计原则
  • 封装性非常好
缺点
  • 子类太多,容易造成类膨胀
使用场景
  • 行为随状态改变而改变的场景
  • 条件、分支判断语句的替代者
注意事项

状态模式适用于当某个对象在它的状态发生改变时,它的行为也随着发生比较大的变化,也就是说在行为受状态约束的情况下可以使用状态模式,而且使用时对象的状态最好不要超过5个。

十、解释器模式(Interpreter Pattern)

10.1 定义

解释器模式是一种按照规定语法进行解析的方案。
Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。

10.2 通用代码

抽象表达式
package designpattern.interpreter;


import java.util.HashMap;

public abstract class Expression {
	//每个表达式必须有一个解析任务
	public abstract Object interpreter(Object ctx);
}

终结符表达式
package designpattern.interpreter;

import java.util.HashMap;

public class TerminalExpression extends Expression {

	//通常终结符表达式只有一个,但是有多个对象
	@Override
	public Object interpreter(Object ctx) {
		return null;
	}
}
非终结符表达式
package designpattern.interpreter;


public class NonTerminalExpression extends Expression {

	//每个非终结符表达式都会对其他表达式产生依赖
	public NonTerminalExpression(Expression... expressions) {

	}

	@Override
	public Object interpreter(Object ctx) {
		//进行文法处理
		return null;
	}
}

客户类
package designpattern.interpreter;

import java.util.Stack;

public class Client {
	public static void main(String[] args) {
		Object ctx = new Object();
		//通常定一个语法容器,容纳一个具体的表达式,
		//通常为ListArray、LinkedList、Stack等类型
		Stack<Expression> stack = new Stack<>();
		for (;;) {
			//进行语法判断,并产生递归调用
			stack.push(new NonTerminalExpression());
			stack.push( new TerminalExpression());
			break;
		}
		//产生一个完整的语法树,由各个具体的语法分析进行解析
		Expression exp = stack.pop();
		//具体元素进入场景
		exp.interpreter(ctx);
	}
}

10.3 应用

优点

解释器是一个简单语法分析工具,它最显著的优点就是扩展性,修改语法规则只要修改相应的非终结符表达式就可以了,若扩展语法,则只要增加非终结符类就可以了。

缺点
  • 解释器模式会引起类膨胀
  • 解释器模式采用递归调用方法
  • 效率问题
使用场景
  • 重复发生的问题可以使使用解释器模式
  • 一个简单语法需要解释的场景
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值