设计模式之【命令模式】,方法调用的花式玩法

news2024/11/14 16:52:43

文章目录

  • 一、什么是命令模式
    • 1、命令模式使用场景
    • 2、命令模式的主要角色
    • 3、命令模式优缺点
    • 4、命令模式注意事项及细节
  • 二、使用示例
    • 1、命令模式的一般写法
    • 2、播放器功能案例
    • 3、遥控器案例
  • 三、源码中的命令模式
    • 1、Thread

一、什么是命令模式

命令模式(Command Pattern)是对命令的封装,每一个命令都是一个操作:请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行操作。命令模式解耦了请求方和接收方,请求方只需请求执行命令,不用关心命令是怎样被接受,怎样被操作以及是否被执行等。命令模式属于行为型模式。

原文:将一个请求封装成医德对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。

在软件系统中,行为请求者与行为实现者通常是一种紧耦合关系,因为这样的实现简单明了。但紧耦合关系缺乏扩展性,在某些场合中,当需要为行为进行记录,撤销或重做等处理时,只能修改源码。而命令模式通过为请求与实现间引入了一个抽象命令接口,解耦了请求与实现,并且中间件是抽象的,它可以有不同的子类实现,因此其具备扩展性。所以,命令模式的本质是解耦命令请求与处理。

1、命令模式使用场景

当系统的某项操作具备命令语义时,且命令实现不稳定(变化),那么可以通过命令模式解耦请求与实现,利用抽象命令接口使请求方代码架构稳定,封装接收方具体命令实现细节。接收方与抽象命令接口呈现弱耦合(内部方法无需一致),具备良好的扩展性。命令模式适用于以下应用场景:

  • 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
  • 现实语义中具备“命令”的操作(如命令菜单、shell命令等)。
  • 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
  • 系统需要在不同的时间指定请求、将请求排队和执行请求。
  • 需要支持命令宏(即命令组合操作)。

2、命令模式的主要角色

在这里插入图片描述
命令模式包含以下主要角色:

  • 抽象命令类(Command)角色: 定义命令的接口,声明执行的方法。
  • 具体命令(Concrete Command)角色:具体的命令,实现命令接口;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
  • 实现者/接收者(Receiver)角色: 接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
  • 调用者/请求者(Invoker)角色: 要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。

从命令模式的UML类图中可以看出:Command的出现就是作为Receiver和Invoker的中间件,解耦了彼此。而之所以引入Command中间件,主要有以下两方面的原因:
(1)解耦请求与实现:即解耦了Invoker和Receiver,因为在UML类图中,Invoker是一个具体的实现,等待接收客户端传入命令(即Invoker与客户端耦合),Invoker处于业务逻辑区域,应当是一个稳定的结构。而Receiver是属于业务功能模块,是经常变动的;如果没有Command,则Invoker紧耦合Receiver,一个稳定的结构依赖了一个不稳定的结构,就会导致整个结构都不稳定了。这也就是Command引入的原因:不仅仅是解耦请求与实现,同时稳定(Invoker)依赖文档(Command),结构还是稳定的。
(2)扩展性增强:扩展性体现在两个方面:① Receiver属于底层细节,可以通过更换不同的Receiver达到不同的细节实现;② Command接口本身就是抽象的,本身就具备扩展性,而且由于命令对象本身就具备抽象,如果结合装饰器模式,功能扩展简直如鱼得水。

注!在一个系统中,不同的命令对应不同的请求,也就是说无法把请求抽象化,因此命令模式中的Receiver是具体实现;但是如果在某一个模块中,可以对Receiver进行抽象,其实这就变相使用到了桥接模式(Command类具备两个变化的维度:Command和Receiver),这样子的扩展性会更加优秀。

3、命令模式优缺点

优点:

  • 降低系统的耦合度。命令模式能将调用操作的对象与实现该操作的对象解耦。
  • 增加或删除命令非常方便。采用命令模式增加与删除命令不会影响其他类,它满足“开闭原则”,对扩展比较灵活。
  • 可以实现宏命令。命令模式可以与组合模式结合,将多个命令装配成一个组合命令,即宏命令。
  • 方便实现 Undo 和 Redo 操作。命令模式可以与备忘录模式结合,实现命令的撤销与恢复。
  • 可以在现有命令的基础上,增加额外功能(比如日志记录等等,结合装饰器模式效果更佳)。

缺点:

  • 使用命令模式可能会导致某些系统有过多的具体命令类。
  • 命令模式的结果其实就是接收方的执行结果,但是为了以命令的形式进行架构,解耦请求与实现,引入了额外类型结构(引入了请求方与抽象命令接口),增加了理解上的困难(不过这也是设计模式带来的一个通病,抽象必然会引入额外类型;抽象肯定比紧密难理解)。
  • 使用频率低、理解难度大,只在非常特定的应用场景下才会用到。

4、命令模式注意事项及细节

  • 将发起请求的对象与执行请求的对象解耦。发起请求的对象是调用者,调用者只要调用命令对象execute()方法就可以让接收者工作,而不必知道具体的接收者对象是谁、是如何实现的,命令对象会负责让接收者执行请求的动作,也就是说:“请求发起者”和“请求执行者”之间的解耦是通过命令对象实现的,命令对象起到了纽带桥梁的作用。
  • 容易设计一个命令队列,只要把命令对象放到队列,就可以多线程的执行命令。
  • 容易实现对请求的撤销和重做。
  • 空命令也是一种设计模式,它为我们省去了判空的操作。可以使用接口适配器模式,将Command接口适配为一个空类。

二、使用示例

1、命令模式的一般写法

//抽象命令接口
public interface ICommand {
    void execute();
}

//具体命令
public class ConcreteCommand implements ICommand {
    // 直接创建接收者,不暴露给客户端
    private Receiver mReceiver;

    public ConcreteCommand(Receiver mReceiver) {
        this.mReceiver = mReceiver;
    }

    public void execute() {
        this.mReceiver.action();
    }
}
//请求者
public class Invoker {
    private ICommand mCmd;

    public Invoker(ICommand cmd) {
        this.mCmd = cmd;
    }

    public void action() {
        this.mCmd.execute();
    }
}
//接收者
public class Receiver {
    public void action() {
        System.out.println("执行具体操作");
    }
}
public class Test {
    public static void main(String[] args) {
        ICommand cmd = new ConcreteCommand(new Receiver());
        Invoker invoker = new Invoker(cmd);
        invoker.action();
    }
}

2、播放器功能案例

假如我们自己开发一个播放器,播放器有播放功能、拖拽进度条功能、停止播放功能、暂停播放功能,我们自己去操作播放器的时候并不是直接调用播放器的方法,而是通过一个控制条去传达指令给播放器内核,那么具体传达什么指令,会被封装为一个个的按钮。那么每个按钮就相当于是对一条命令的封装。用控制条实现了用户发送指令与播放器内核接收指令的解耦。

// Receiver角色:播放器内核GPlayer
public class GPlayer {
    public void play(){
        System.out.println("正常播放");
    }

    public void speed(){
        System.out.println("拖动进度条");
    }

    public void stop(){
        System.out.println("停止播放");
    }

    public void pause(){
        System.out.println("暂停播放");
    }
}

// 抽象命令Command角色:命令接口
public interface IAction {
    void execute();
}

// 具体命令角色
public class StopAction implements IAction {
    private GPlayer gplayer;

    public StopAction(GPlayer gplayer) {
        this.gplayer = gplayer;
    }

    public void execute() {
        gplayer.stop();
    }
}

public class PauseAction implements IAction {
    private GPlayer gplayer;

    public PauseAction(GPlayer gplayer) {
        this.gplayer = gplayer;
    }

    public void execute() {
        gplayer.pause();
    }
}

public class PlayAction implements IAction {
    private GPlayer gplayer;

    public PlayAction(GPlayer gplayer) {
        this.gplayer = gplayer;
    }

    public void execute() {
        gplayer.play();
    }
}

public class SpeedAction implements IAction {
    private GPlayer gplayer;

    public SpeedAction(GPlayer gplayer) {
        this.gplayer = gplayer;
    }

    public void execute() {
        gplayer.speed();
    }
}

// Invoker 角色
public class Controller {
    private List<IAction> actions = new ArrayList<IAction>();

    public void addAction(IAction action){
        actions.add(action);
    }

    public void execute(IAction action){
        action.execute();
    }

    public void executes(){
        for (IAction action:actions) {
            action.execute();
        }
        actions.clear();
    }
}
public class Test {
    public static void main(String[] args) {

        GPlayer player = new GPlayer();
        Controller controller = new Controller();
        controller.execute(new PlayAction(player));

        controller.addAction(new PauseAction(player));
        controller.addAction(new PlayAction(player));
        controller.addAction(new StopAction(player));
        controller.addAction(new SpeedAction(player));
        controller.executes();
    }
}

3、遥控器案例

买了一套智能家电,有点灯、风扇、冰箱、洗衣机、电视机,我们只需要在手机上安装app就可以控制这些家电。

//创建命令接口
public interface Command {

	//执行动作(操作)
	public void execute();
	//撤销动作(操作)
	public void undo();
}

/**
 * 没有任何命令,即空执行: 用于初始化每个按钮, 当调用空命令时,对象什么都不做
 * 其实,这样是一种设计模式, 可以省掉对空判断
 */
public class NoCommand implements Command {

	@Override
	public void execute() {
	}

	@Override
	public void undo() {
	}
}

// 电灯Receiver
public class LightReceiver {

	public void on() {
		System.out.println(" 电灯打开了.. ");
	}
	
	public void off() {
		System.out.println(" 电灯关闭了.. ");
	}
}
// 电灯具体命令类
public class LightOffCommand implements Command {

	// 聚合LightReceiver
	LightReceiver light;

	// 构造器
	public LightOffCommand(LightReceiver light) {
			super();
			this.light = light;
		}

	@Override
	public void execute() {
		// 调用接收者的方法
		light.off();
	}

	@Override
	public void undo() {
		// 调用接收者的方法
		light.on();
	}
}
// 电灯具体命令类
public class LightOnCommand implements Command {

	//聚合LightReceiver
	LightReceiver light;
	
	//构造器
	public LightOnCommand(LightReceiver light) {
		super();
		this.light = light;
	}
	
	@Override
	public void execute() {
		//调用接收者的方法
		light.on();
	}

	@Override
	public void undo() {
		//调用接收者的方法
		light.off();
	}
}

// 电视机Receiver
public class TVReceiver {
	
	public void on() {
		System.out.println(" 电视机打开了.. ");
	}
	
	public void off() {
		System.out.println(" 电视机关闭了.. ");
	}
}
// 电视机具体命令
public class TVOnCommand implements Command {

	// 聚合TVReceiver
	TVReceiver tv;

	// 构造器
	public TVOnCommand(TVReceiver tv) {
		super();
		this.tv = tv;
	}

	@Override
	public void execute() {
		// 调用接收者的方法
		tv.on();
	}

	@Override
	public void undo() {
		// 调用接收者的方法
		tv.off();
	}
}

public class TVOffCommand implements Command {

	// 聚合TVReceiver
	TVReceiver tv;

	// 构造器
	public TVOffCommand(TVReceiver tv) {
		super();
		this.tv = tv;
	}

	@Override
	public void execute() {
		// 调用接收者的方法
		tv.off();
	}

	@Override
	public void undo() {
		// 调用接收者的方法
		tv.on();
	}
}

// 控制器,Invoker角色
public class RemoteController {

	// 开 按钮的命令数组
	Command[] onCommands;
	Command[] offCommands;

	// 执行撤销的命令
	Command undoCommand;

	// 构造器,完成对按钮初始化

	public RemoteController() {

		onCommands = new Command[5];
		offCommands = new Command[5];

		for (int i = 0; i < 5; i++) {
			onCommands[i] = new NoCommand();
			offCommands[i] = new NoCommand();
		}
	}

	// 给我们的按钮设置你需要的命令
	public void setCommand(int no, Command onCommand, Command offCommand) {
		onCommands[no] = onCommand;
		offCommands[no] = offCommand;
	}

	// 按下开按钮
	public void onButtonWasPushed(int no) { // no 0
		// 找到你按下的开的按钮, 并调用对应方法
		onCommands[no].execute();
		// 记录这次的操作,用于撤销
		undoCommand = onCommands[no];

	}

	// 按下开按钮
	public void offButtonWasPushed(int no) { // no 0
		// 找到你按下的关的按钮, 并调用对应方法
		offCommands[no].execute();
		// 记录这次的操作,用于撤销
		undoCommand = offCommands[no];

	}
	
	// 按下撤销按钮
	public void undoButtonWasPushed() {
		undoCommand.undo();
	}

}

// 客户端
public class Client {

	public static void main(String[] args) {
		
		//使用命令设计模式,完成通过遥控器,对电灯的操作
		
		//创建电灯的对象(接受者)
		LightReceiver lightReceiver = new LightReceiver();
		
		//创建电灯相关的开关命令
		LightOnCommand lightOnCommand = new LightOnCommand(lightReceiver);
		LightOffCommand lightOffCommand = new LightOffCommand(lightReceiver);
		
		//需要一个遥控器
		RemoteController remoteController = new RemoteController();
		
		//给我们的遥控器设置命令, 比如 no = 0 是电灯的开和关的操作
		remoteController.setCommand(0, lightOnCommand, lightOffCommand);
		
		System.out.println("--------按下灯的开按钮-----------");
		remoteController.onButtonWasPushed(0);
		System.out.println("--------按下灯的关按钮-----------");
		remoteController.offButtonWasPushed(0);
		System.out.println("--------按下撤销按钮-----------");
		remoteController.undoButtonWasPushed();
		
		
		System.out.println("=========使用遥控器操作电视机==========");
		
		TVReceiver tvReceiver = new TVReceiver();
		
		TVOffCommand tvOffCommand = new TVOffCommand(tvReceiver);
		TVOnCommand tvOnCommand = new TVOnCommand(tvReceiver);
		
		//给我们的遥控器设置命令, 比如 no = 1 是电视机的开和关的操作
		remoteController.setCommand(1, tvOnCommand, tvOffCommand);
		
		System.out.println("--------按下电视机的开按钮-----------");
		remoteController.onButtonWasPushed(1);
		System.out.println("--------按下电视机的关按钮-----------");
		remoteController.offButtonWasPushed(1);
		System.out.println("--------按下撤销按钮-----------");
		remoteController.undoButtonWasPushed();
	}
}

三、源码中的命令模式

1、Thread

Runable是一个典型命令模式,Runnable担当命令的角色,Thread充当的是调用者,start方法就是其执行方法。

//命令接口(抽象命令角色)
public interface Runnable {
	public abstract void run();
}
//调用者
public class Thread implements Runnable {
	private Runnable target;
	public synchronized void start() {
		if (threadStatus != 0)
			throw new IllegalThreadStateException();
		group.add(this);
		boolean started = false;
		try {
			start0();
			started = true;
		} finally {
		try {
			if (!started) {
				group.threadStartFailed(this);
			}
			} catch (Throwable ignore) {
			}
		}
	}
	private native void start0();
}

会调用一个native方法start0(),调用系统方法,开启一个线程。而接收者是对程序员开放的,可以自己定义接收者。

/**
* jdk Runnable 命令模式
* TurnOffThread : 属于具体
*/
public class TurnOffThread implements Runnable{
	private Receiver receiver;
	public TurnOffThread(Receiver receiver) {
		this.receiver = receiver;
	}
	public void run() {
		receiver.turnOFF();
	}
}
/**
* 测试类
*/
public class Demo {
	public static void main(String[] args) {
		Receiver receiver = new Receiver();
		TurnOffThread turnOffThread = new TurnOffThread(receiver);
		Thread thread = new Thread(turnOffThread);
		thread.start();
	}
}

实际上调用线程的start方法之后,就有资格去抢CPU资源,而不需要我们自己编写获得CPU资源的逻辑。而线程抢到CPU资源后,就会执行run方法中的内容,用Runnable接口把用户请求和CPU执行进行了解耦。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/535982.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

图像分割标注工具——QuPath使用说明

0、QuPath资源一览 QuPath是一款病理学和生物图像定量分析的软件&#xff0c;支持多种标注方式。一些常用资源如下&#xff1a; 官网&#xff1a;QuPath 官方文档&#xff1a;https://qupath.readthedocs.io/en/stable/docs/intro/index.html 软件下载列表&#xff1a;http…

搜狗主动推送工具-搜狗推送接口自动推送

想要让自己的网站被搜狗快速收录&#xff0c;以下是一些优化建议&#xff1a; 提交网站地图&#xff1a;将网站地图提交到搜狗搜索引擎&#xff0c;能够让搜索引擎更快速地爬取和发现网站所有的页面。同时在网站地图中应该包含网站所有页面的链接&#xff0c;方便搜狗搜索引擎爬…

【读书笔记】《亲密关系》

作者&#xff1a;美国的罗兰米勒 刚拿到这本书的时候&#xff0c;就被最后将近100页的参考文献折服了&#xff0c;让我认为这本书极具专业性。 作者使用了14章&#xff0c;从人与人之间是如何相互吸引的&#xff0c;讲到如何相处与沟通&#xff0c;后又讲到如何面对冲突与解决矛…

openAI国内的免费镜像网站列表分享

1.ChatGPT For Free 地址&#xff1a;https://gpt4.gravityengine.cc/ 2.老北鼻AI智能助手 地址&#xff1a;https://739167295.ai201.live/ 3.AIChatOS 地址&#xff1a;https://chat.jinshutuan.com/#/chat/1684287150613 4.AIGPT 地址&#xff1a;http://20200.cn…

【Linux命令】mount / umount命令、查看文件的挂载情况(lsblk)

在Windows环境下&#xff0c;我们可以直接访问检测到的外部设备&#xff0c;如磁盘、U盘等&#xff1b;然而在Linux环境下&#xff0c;外部硬件设备如磁盘、SD卡等外部设备是无法直接访问的。因此就需要挂载。 参考链接&#xff1a;mount 详解 目录 1、什么是挂载&#xff1f;…

使用Vivado创建一个点亮FPGALED灯的项目

说明 1、本文针对没有使用过Vivado&#xff0c;也不知道如何用Vivado创建一个项目的朋友。 2、本文内容为用Vivado创建一个点亮FPGA LED灯项目的全部流程。 正文 1、创建一个新项目&#xff0c;点击创建新项目&#xff0c;并点击next。 2、选择项目名称和项目保存路径。 3、…

时间序列-相关性-ACF PACF CCF

一、自相关系数&#xff1a; 衡量的是同一个时间序列内的两个不同的时间段的相关性 弱平稳 If波动&#xff0c;波动幅度也是固定的。 相关图 不同时间间隔的相关系数算出来并且绘制在图中 例&#xff1a;(python) 分析&#xff1a; ①当时间间隔为0的时候&#xff0c;相关系…

【MongoDB】MongoDB分布式文件存储的数据库

一、数据库简介 1、数据库 数据库是按照数据结构来组织、存储和管理数据的仓库&#xff1b;我们的程序都是在内存中运行的&#xff0c;一旦程序运行结束或者计算机断电&#xff0c;程序运行中的数据都会丢失&#xff1b;所以我们就需要将一些程序运行的数据持久化到硬盘中&am…

计算机信息安全保护等级划分为五个安全级别

《计算机信息安全保护等级划分准则》将计算机信息安全保护等级划分为五个安全级别&#xff1a; 安全级别级别名称是否需要备案对公民、法人和其他组织的合法权益造成的损害程度对社会秩序、公共利益造成的损害程度对国家安全造成的损害程度适用范围重要程度第一级自主保护级无…

智能感知编码优化与落地实践

作者 | XHF 导读 基于人眼视觉特性出发的感知编码优化技术&#xff0c;成为互联网短视频、OTT 等 UGC 场景的重点优化手段&#xff0c;可以在降低视频码率的同时&#xff0c;提升视频的观看体验。 今天主要有 4 个方面的内容。首先给大家介绍一下感知编码的技术背景&#xff1b…

论性价比,这家奥威BI大数据分析平台很能打

论性价比&#xff0c;国产BI大数据分析平台几乎是毫无悬念地胜过大多数外国BI&#xff0c;而在国产BI大数据分析平台里&#xff0c;奥威BI的性价比也是出了名地高。在同等价位的BI大数据分析平台中&#xff0c;奥威BI大数据分析平台不仅能提供智能高效的数据分析功能、花样繁多…

推动飞盘运动发展 冯氏集团承办中国飞盘联赛·上海站获圆满成功

5月14日下午&#xff0c;由冯氏集团主承办的2022-2023年中国飞盘联赛 上海站在上海市民体育公园足球公园圆满落幕&#xff0c;这是冯氏集团继去年创立飞盘俱乐部冠军赛&#xff08;Ultimate Clubs Championship Series&#xff0c;简称UCCS&#xff09;后&#xff0c;在飞盘及城…

springboot+jsp法律知识分享网站普法平台

法律知识分享平台&#xff0c;主要的模块包括查看主页、个人中心、用户管理、律师事务所管理、律师管理、法律资讯管理、案例分析管理、案例分享管理、法规信息管理、法规分享管理、留言信息管理、留言回复管理、论坛管理、系统管理等功能。系统中管理员主要是为了安全有效地存…

【教程】Warp/ZeroTrust 1.1.1.1 域名解析服务的安装与使用

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 目录 扫盲 安装 验证 说明 扫盲 1.1.1.1是一款免费的域名解析服务&#xff0c;也就是域名服务器&#xff0c;由CloudFlare与APNIC共同拥有与维护。该服务于2018年4月1日发表启用&#xff0c;且被Cloudflare称…

全局异常处理器

文章目录 一、全局异常处理器1.1 程序1.2 ControllerAdvice 注解 二、封装结果集 一、全局异常处理器 各层代码出现异常&#xff0c;我们是如何处理的&#xff1f; ​ 未做处理。 ​ 如果是在Mapper层出现异常&#xff0c;会抛给Service&#xff0c;Service会抛给Controller…

基于Java+SpringBoot制作一个论坛小程序

制作一个论坛互动平台,让兴趣志同道合者用户聚集在这里交流话题、展示自我、结交朋友。 一、小程序1.1 项目创建1.2 首页1.3 论坛板块页1.4 个人中心页1.5 帖子详情页二、API2.1 SpringBoot框架搭建

基于html+css的图展示74

准备项目 项目开发工具 Visual Studio Code 1.44.2 版本: 1.44.2 提交: ff915844119ce9485abfe8aa9076ec76b5300ddd 日期: 2020-04-16T16:36:23.138Z Electron: 7.1.11 Chrome: 78.0.3904.130 Node.js: 12.8.1 V8: 7.8.279.23-electron.0 OS: Windows_NT x64 10.0.19044 项目…

进程线程基本知识

1 进程 我们编写的代码只是一个存储在硬盘的静态文件&#xff0c;通过编译后就会生成二进制可执行文件&#xff0c;当我们运行这个可执行文件后&#xff0c;它会被装载到内存中&#xff0c;接着 CPU 会执行程序中的每一条指令&#xff0c;那么这个运行中的程序&#xff0c;就被…

springboot+java网上求职人才招聘网站 s0rp8

本人才招聘网站采用Java技术&#xff0c;Mysql数据库开发&#xff0c;充分保证了系统稳定性、完整性。 人才招聘网站的设计与实现的设计思想如下&#xff1a; Spring Boot 是 Spring 家族中的一个全新的框架&#xff0c;它用来简化Spring应用程序的创建和开发过程。也可以说 …

期刊介绍|中科院一区8+期刊,影响因子飞涨,国人友好,明显扩刊趋势!

今天给大家介绍一本期刊&#xff1a;Hepatobiliary Surgery and Nutrition&#xff1b; 一、基本信息: 1、期刊名称&#xff1a;Hepatobiliary Surgery and Nutrition&#xff1b; 2、期刊ISSN&#xff1a;1054-139X&#xff1b; 3、出版商&#xff1a;Elsevier USA&#xff1b…