设计模式—— 十五 :命令模式

什么是命令模式?

命令模式的定义:

Encapsulate a request as an object,thereby letting you parameterize clients with different requests,queue or log requests,and support undoable operations.(将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。)

命令模式的核心在于引入了命令类,通过命令类来降低发送者和接收者的耦合度,请求发送 者只需指定一个命令对象,再通过命令对象来调用请求接收者的处理方法。

命令模式通用类图如下:

图15-1:命令模式模式通用类图

在这里插入图片描述

命令模式包含这么几个角色:

  • Command(抽象命令):声明需要执行的命令
  • ConcreteCommand(具体命令):实现声明的命令
  • Receive(接收者):接收者执行与请求相关的操作,它具体实现对请求的业务处理
  • Invoker(调用者):调用者即请求发送者,它通过命令对象来执行请求。

命令模式的本质是对请求进行封装,一个请求对应于一个命令,将发出命令的责任和执行命令的责任分割开。每一个命令都是一个操作:请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行相应的操作。命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求如何被接收、操作是否被执行、何时被执行,以及是怎么被执行的。

命令模式通用代码如下:

  • Receiver:Receiver类实现具体的业务需求
复制代码
<span style="color:#141418"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#a0a1a7"><em>/**
 * <span style="color:#a626a4">@author</span> 三分恶
 * <span style="color:#a626a4">@date</span> 2020年6月28日
 * <span style="color:#a626a4">@description</span> 接收者
 */</em></span>
<span style="color:#a626a4">public</span> <span style="color:#a626a4">class</span> <span style="color:#4078f2">Receiver</span> {
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">doSomething</span>() {
		<span style="color:#a0a1a7"><em>//具体的业务逻辑</em></span>
	}
}
</code></span></span>
  • 抽象的Command类:
复制代码
<span style="color:#141418"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#a0a1a7"><em>/**
 * <span style="color:#a626a4">@author</span> 三分恶
 * <span style="color:#a626a4">@date</span> 2020年6月28日
 * <span style="color:#a626a4">@description</span> 抽象的Command类
 */</em></span>
<span style="color:#a626a4">public</span> <span style="color:#a626a4">abstract</span> <span style="color:#a626a4">class</span> <span style="color:#4078f2">Command</span> {
	<span style="color:#a0a1a7"><em>// 每个命令类都必须有一个执行命令的方法</em></span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">abstract</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">execute</span>();
}

</code></span></span>
  • 具体的Command类:根据需求,具体的命令类可以有多个:
复制代码
<span style="color:#141418"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#a0a1a7"><em>/**
 * <span style="color:#a626a4">@author</span> 三分恶
 * <span style="color:#a626a4">@date</span> 2020年6月28日
 * <span style="color:#a626a4">@description</span> 具体的命令类
 */</em></span>
<span style="color:#a626a4">public</span> <span style="color:#a626a4">class</span> <span style="color:#4078f2">ConcreteCommand</span> <span style="color:#a626a4">extends</span> <span style="color:#4078f2">Command</span> {
	<span style="color:#a0a1a7"><em>// 维持一个对请求接收者对象的引用</em></span>
	<span style="color:#a626a4">private</span> Receiver receiver; 

	<span style="color:#a0a1a7"><em>//构造函数传递接收者</em></span>
	<span style="color:#a626a4">public</span> <span style="color:#4078f2">ConcreteCommand</span>(Receiver receiver) {
		<span style="color:#c18401">this</span>.receiver = receiver;
	}

	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">execute</span>() {
		 <span style="color:#a0a1a7"><em>// 调用请求接收者的业务处理方法doSomething()</em></span>
		receiver.doSomething();
	}
}
</code></span></span>
  • 调用者Invoker类:
复制代码
<span style="color:#141418"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#a0a1a7"><em>/**
 * <span style="color:#a626a4">@author</span> 三分恶
 * <span style="color:#a626a4">@date</span> 2020年6月28日
 * <span style="color:#a626a4">@description</span> 调用者
 */</em></span>
<span style="color:#a626a4">public</span> <span style="color:#a626a4">class</span> <span style="color:#4078f2">Invoker</span> {
	<span style="color:#a626a4">private</span> Command command;
	
	<span style="color:#a0a1a7"><em>// 设值注入</em></span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">setCommand</span>(Command command) {
		<span style="color:#c18401">this</span>.command = command;
	}

	<span style="color:#a0a1a7"><em>// 执行命令</em></span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">action</span>() {
		<span style="color:#c18401">this</span>.command.execute();
	}
}
</code></span></span>
  • 场景类:
复制代码
<span style="color:#141418"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#a0a1a7"><em>/**
 * <span style="color:#a626a4">@author</span> 三分恶
 * <span style="color:#a626a4">@date</span> 2020年6月28日 
 * <span style="color:#a626a4">@description</span>  
 */</em></span>
<span style="color:#a626a4">public</span> <span style="color:#a626a4">class</span> <span style="color:#4078f2">Client</span> {

	<span style="color:#a626a4">public</span> <span style="color:#a626a4">static</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">main</span>(String[] args) {
		<span style="color:#a0a1a7"><em>//首先声明调用者Invoker </em></span>
		<span style="color:#986801">Invoker</span> <span style="color:#986801">invoker</span> <span style="color:#ab5656">=</span> <span style="color:#a626a4">new</span> <span style="color:#4078f2">Invoker</span>(); 
		<span style="color:#a0a1a7"><em>//定义接收者 </em></span>
		<span style="color:#986801">Receiver</span> <span style="color:#986801">receiver</span> <span style="color:#ab5656">=</span> <span style="color:#a626a4">new</span> <span style="color:#4078f2">Receiver</span>(); 
		<span style="color:#a0a1a7"><em>//定义一个发送给接收者的命令 </em></span>
		<span style="color:#986801">Command</span> <span style="color:#986801">command</span> <span style="color:#ab5656">=</span> <span style="color:#a626a4">new</span> <span style="color:#4078f2">ConcreteCommand</span>(receiver); 
		<span style="color:#a0a1a7"><em>//把命令交给调用者去执行 </em></span>
		invoker.setCommand(command); 
		invoker.action();
	}

}
</code></span></span>

为什么要用命令模式?

假设有一个这样的业务场景:一个正在开发的软件项目,分为三个组:需求组、美工组、开发组。在开发的过程中,客户需要和厂商沟通,和需求组讨论需求、和 美工讨论页面、和代码组讨论实现,告诉他们修改、删除、增加各种内容等。

使用命令模式前

上面的业务场景抽象成类图:

图15-2:甲方要求业务场景初始类图

在这里插入图片描述

根据类图进行具体的编码实现:

  • Group:抽象类,定义业务:
复制代码
<span style="color:#141418"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#a0a1a7"><em>/**
 * <span style="color:#a626a4">@author</span> 三分恶
 * <span style="color:#a626a4">@date</span> 2020年6月28日
 * <span style="color:#a626a4">@description</span> 抽象Group
 */</em></span>
<span style="color:#a626a4">public</span> <span style="color:#a626a4">abstract</span> <span style="color:#a626a4">class</span> <span style="color:#4078f2">Group</span> {
	<span style="color:#a0a1a7"><em>// 甲乙双方分开办公,如果甲方要和某个组讨论,首先要找到这个组</em></span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">abstract</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">find</span>();

	<span style="color:#a0a1a7"><em>// 要求增加功能</em></span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">abstract</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">add</span>();

	<span style="color:#a0a1a7"><em>// 要求删除功能</em></span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">abstract</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">delete</span>();

	<span style="color:#a0a1a7"><em>// 要求修改功能</em></span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">abstract</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">change</span>();

	<span style="color:#a0a1a7"><em>// 要求给出所有的变更计划</em></span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">abstract</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">plan</span>();
}

</code></span></span>
  • RequirementGroup(需求组):
复制代码
<span style="color:#141418"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#a626a4">public</span> <span style="color:#a626a4">class</span> <span style="color:#4078f2">RequirementGroup</span> <span style="color:#a626a4">extends</span> <span style="color:#4078f2">Group</span>{

	<span style="color:#4078f2">@Override</span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">find</span>() {
		System.out.println(<span style="color:#50a14f">"找到需求组..."</span>);
	}

	<span style="color:#4078f2">@Override</span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">add</span>() {
		System.out.println(<span style="color:#50a14f">"客户要求增加一项需求..."</span>);
	}

	<span style="color:#4078f2">@Override</span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">delete</span>() {
		System.out.println(<span style="color:#50a14f">"客户要求删除一项需求..."</span>);
	}

	<span style="color:#4078f2">@Override</span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">change</span>() {
		System.out.println(<span style="color:#50a14f">"客户要求修改一项需求..."</span>);
	}

	<span style="color:#4078f2">@Override</span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">plan</span>() {
		System.out.println(<span style="color:#50a14f">"客户要求需求变更计划..."</span>);
	}

}
</code></span></span>
  • PageGroup(美工组):
复制代码
<span style="color:#141418"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#a626a4">public</span> <span style="color:#a626a4">class</span> <span style="color:#4078f2">PageGroup</span> <span style="color:#a626a4">extends</span> <span style="color:#4078f2">Group</span>{

	<span style="color:#4078f2">@Override</span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">find</span>() {
		System.out.println(<span style="color:#50a14f">"找到美工组..."</span>);
	}

	<span style="color:#4078f2">@Override</span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">add</span>() {
		System.out.println(<span style="color:#50a14f">"客户要求增加一个页面..."</span>);
	}

	<span style="color:#4078f2">@Override</span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">delete</span>() {
		System.out.println(<span style="color:#50a14f">"客户要求删除一个页面..."</span>);
	}

	<span style="color:#4078f2">@Override</span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">change</span>() {
		System.out.println(<span style="color:#50a14f">"客户要求改变一个页面..."</span>);
	}

	<span style="color:#4078f2">@Override</span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">plan</span>() {
		System.out.println(<span style="color:#50a14f">"客户要求页面变更计划..."</span>);
	}

}
</code></span></span>
  • CodeGroup(开发组):
复制代码
<span style="color:#141418"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#a626a4">public</span> <span style="color:#a626a4">class</span> <span style="color:#4078f2">CodeGroup</span> <span style="color:#a626a4">extends</span> <span style="color:#4078f2">Group</span>{

	<span style="color:#4078f2">@Override</span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">find</span>() {
		System.out.println(<span style="color:#50a14f">"找到代码组..."</span>);
	}

	<span style="color:#4078f2">@Override</span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">add</span>() {
		System.out.println(<span style="color:#50a14f">"客户要求增加一项功能..."</span>);
	}

	<span style="color:#4078f2">@Override</span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">delete</span>() {
		System.out.println(<span style="color:#50a14f">"客户要求删除一项功能..."</span>);
	}

	<span style="color:#4078f2">@Override</span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">change</span>() {
		System.out.println(<span style="color:#50a14f">"客户要求修改一项功能..."</span>);
	}

	<span style="color:#4078f2">@Override</span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">plan</span>() {
		System.out.println(<span style="color:#50a14f">"客户要求代码变更计划..."</span>);
	}

}
</code></span></span>
  • 场景类:
复制代码
<span style="color:#141418"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#a626a4">public</span> <span style="color:#a626a4">class</span> <span style="color:#4078f2">Client</span> {

	<span style="color:#a0a1a7"><em>/**
	 * <span style="color:#a626a4">@param</span> args
	 */</em></span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">static</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">main</span>(String[] args) {
		<span style="color:#a0a1a7"><em>//首先客户找到需求组说,过来谈需求,并修改</em></span>
		System.out.println(<span style="color:#50a14f">"-----------客户要求增加一项需求---------------"</span>); 
		<span style="color:#986801">Group</span> <span style="color:#986801">rg</span> <span style="color:#ab5656">=</span> <span style="color:#a626a4">new</span> <span style="color:#4078f2">RequirementGroup</span>();
		<span style="color:#a0a1a7"><em>//找到需求组</em></span>
		rg.find(); 
		<span style="color:#a0a1a7"><em>//增加一个需求 </em></span>
		rg.add(); 
		<span style="color:#a0a1a7"><em>//要求变更计划 </em></span>
		rg.plan();
	}

}
</code></span></span>

运行结果:

在这里插入图片描述

场景类中客户找到了需求组,向需求组提出了增加需求和需求变更的要求。

这样存在什么问题呢?甲方对乙方做一些要求的时候,要找到对应的组,但是不能希望甲方是非常专业的,可能提需求提到了开发组头上,要求页面变更提到了需求组头上。

使用命令模式后

这是为什么项目需要项目经理的原因之一。

甲方不管你什么需求、美工、开发,只管把项目经理叫过去,告诉项目经理他们的要求。项目经理再根据甲方的要求向各个组下达命令。对应的,就可以引入命令模式。

图15-3:甲方要求业务场景引入命令模式的类图

在这里插入图片描述

来看看具体的代码:

  • 抽象命令类:
复制代码
<span style="color:#141418"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#a626a4">public</span> <span style="color:#a626a4">abstract</span>  <span style="color:#a626a4">class</span> <span style="color:#4078f2">Command</span> {
	<span style="color:#a0a1a7"><em>//把三个组都定义好,子类可以直接使用 </em></span>
	<span style="color:#a626a4">protected</span> <span style="color:#986801">RequirementGroup</span> <span style="color:#986801">rg</span> <span style="color:#ab5656">=</span> <span style="color:#a626a4">new</span> <span style="color:#4078f2">RequirementGroup</span>();   <span style="color:#a0a1a7"><em>//需求组</em></span>
	<span style="color:#a626a4">protected</span> <span style="color:#986801">PageGroup</span> <span style="color:#986801">pg</span> <span style="color:#ab5656">=</span> <span style="color:#a626a4">new</span> <span style="color:#4078f2">PageGroup</span>(); <span style="color:#a0a1a7"><em>//美工组 </em></span>
	<span style="color:#a626a4">protected</span> <span style="color:#986801">CodeGroup</span> <span style="color:#986801">cg</span> <span style="color:#ab5656">=</span> <span style="color:#a626a4">new</span> <span style="color:#4078f2">CodeGroup</span>(); <span style="color:#a0a1a7"><em>//代码组 </em></span>
	<span style="color:#a0a1a7"><em>//只有一个方法,你要我做什么事情 </em></span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">abstract</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">execute</span>();
}
</code></span></span>
  • 增加需求的命令:
复制代码
<span style="color:#141418"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#a626a4">public</span> <span style="color:#a626a4">class</span> <span style="color:#4078f2">AddRequirementCommand</span> <span style="color:#a626a4">extends</span> <span style="color:#4078f2">Command</span>{

	<span style="color:#4078f2">@Override</span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">execute</span>() {
		<span style="color:#a0a1a7"><em>//找到需求组 </em></span>
		<span style="color:#c18401">super</span>.rg.find(); 
		<span style="color:#a0a1a7"><em>//增加一份需求</em></span>
		<span style="color:#c18401">super</span>.rg.add(); 
		<span style="color:#a0a1a7"><em>//给出计划 </em></span>
		<span style="color:#c18401">super</span>.rg.plan();
	}

}
</code></span></span>
  • 删除页面的命令:
复制代码
<span style="color:#141418"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#a626a4">public</span> <span style="color:#a626a4">class</span> <span style="color:#4078f2">DeletePageCommand</span> <span style="color:#a626a4">extends</span> <span style="color:#4078f2">Command</span>{

	<span style="color:#4078f2">@Override</span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">execute</span>() {
		<span style="color:#a0a1a7"><em>//找到页面组 </em></span>
		<span style="color:#c18401">super</span>.pg.find(); 
		<span style="color:#a0a1a7"><em>//删除一个页面 </em></span>
		<span style="color:#c18401">super</span>.rg.delete();
		<span style="color:#a0a1a7"><em>//给出计划 </em></span>
		<span style="color:#c18401">super</span>.rg.plan();
	}

}
</code></span></span>
  • 负责人Invoker:负责人只要接到客户的命令,就立刻执行。
复制代码
<span style="color:#141418"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#a626a4">public</span> <span style="color:#a626a4">class</span> <span style="color:#4078f2">Invoker</span> {
	<span style="color:#a0a1a7"><em>// 什么命令</em></span>
	<span style="color:#a626a4">private</span> Command command;

	<span style="color:#a0a1a7"><em>// 客户发出命令</em></span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">setCommand</span>(Command command) {
		<span style="color:#c18401">this</span>.command = command;
	}

	<span style="color:#a0a1a7"><em>// 执行客户的命令</em></span>
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">action</span>() {
		<span style="color:#c18401">this</span>.command.execute();
	}
}
</code></span></span>
  • 场景类:模拟客户增加需求的命令。
复制代码
<span style="color:#141418"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#a626a4">public</span> <span style="color:#a626a4">class</span> <span style="color:#4078f2">Client</span> {
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">static</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">main</span>(String[] args) {
		<span style="color:#a0a1a7"><em>// 定义调用者</em></span>
		<span style="color:#986801">Invoker</span> <span style="color:#986801">jingli</span> <span style="color:#ab5656">=</span> <span style="color:#a626a4">new</span> <span style="color:#4078f2">Invoker</span>();
		<span style="color:#a0a1a7"><em>// 客户要求增加一项需求</em></span>
		System.out.println(<span style="color:#50a14f">"------------客户要求增加一项需求---------------"</span>);
		<span style="color:#a0a1a7"><em>// 客户下命令</em></span>
		<span style="color:#986801">Command</span> <span style="color:#986801">command</span> <span style="color:#ab5656">=</span> <span style="color:#a626a4">new</span> <span style="color:#4078f2">AddRequirementCommand</span>();
		<span style="color:#a0a1a7"><em>// 调用者接收到命令</em></span>
		jingli.setCommand(command);
		<span style="color:#a0a1a7"><em>// 调用者执行命令</em></span>
		jingli.action();
	}
}
</code></span></span>

场景类就简单了很多,如果客户提出其它要求,如删除页面,只需要:

复制代码
<span style="color:#141418"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#a0a1a7"><em>// 客户下命令</em></span>
<span style="color:#a0a1a7"><em>//Command command = new AddRequirementCommand();</em></span>
<span style="color:#986801">Command</span> <span style="color:#986801">command</span> <span style="color:#ab5656">=</span> <span style="color:#a626a4">new</span> <span style="color:#4078f2">DeletePageCommand</span>();
</code></span></span>

同样比较简单。

这样一来,客户提要求的时候,不需要知道具体谁去完成这个要求,只需求把这个要求提给项目经理即可。

高内聚的要求就被满足了。

命令模式优缺点

优点

● 类间解耦
调用者角色与接收者角色之间没有任何依赖关系,调用者实现功能时只需调用Command 抽象类的execute方法就可以,不需要了解到底是哪个接收者执行。

● 可扩展性 Command的子类可以非常容易地扩展,而调用者Invoker和高层次的模块Client不产生严 重的代码耦合。

缺点

使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个对请求接收者的调 用操作都需要设计一个具体命令类,因此在某些系统中可能需要提供大量的具体命令类,这 将影响命令模式的使用。

命令模式使用场景

在以下情况下可以考虑使用命令模式:

  • 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。请求调用者 无须知道接收者的存在,也无须知道接收者是谁,接收者也无须关心何时被调用。
  • 系统需要在不同的时间指定请求、将请求排队和执行请求。一个命令对象和请求的初始调 用者可以有不同的生命期,换言之,最初的请求发出者可能已经不在了,而命令对象本身仍 然是活动的,可以通过该命令对象去调用请求接收者,而无须关心请求调用者的存在性,可 以通过请求日志文件等机制来具体实现。
  • 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值