探索设计模式的魅力:掌握命令模式-解锁软件设计的‘遥控器’

在这里插入图片描述
​🌈 个人主页:danci_
🔥 系列专栏:《设计模式》
💪🏻 制定明确可量化的目标,并且坚持默默的做事。


引言:探索命令模式的奥秘

    软件设计领域充满挑战与机遇,命令模式作为关键要素,以优雅方式组织应用程序中的行为和请求。命令模式在现实世界中无处不在,如遥控器按钮或语音助手指令,封装请求或操作为对象,便于灵活处理不同请求、队列、日志及可撤销操作。从简单GUI到复杂企业级事务管理,命令模式均发挥重要作用。
    命令模式的魅力在于其提供的松耦合设计方式。它将发起请求的对象(Invoker)与实现请求的对象(Receiver)之间的依赖解耦,引入了具体命令(ConcreteCommand)类来作为二者之间的沟通桥梁。这不仅增强了系统的灵活性,使得命令的添加和扩展变得更为平易,同时也方便了事务逻辑和历史记录的实现,比如撤销/重做功能,这在诸如文本编辑器等需要这类功能的应用程序中至关重要。
    本文将深入解析命令模式的精粹,从基本概念入手,阐述其在软件设计中的实际应用,探讨如何高效地实现命令模式,并揭示其背后的设计哲学。我们会通过实例验证命令模式的多功能性,并指出在实现过程中需要注意的常见陷阱和挑战。

    文章的结构安排如下:

  • 传统的实现方式
  • 模式讲解
  • 回顾与展望

    随着我们走进命令模式的奥秘世界,将揭示如何巧妙地利用它来构建模块化、灵活和可维护性高的软件系统。

文章目录

  • 一、传统实现方式
    • 场景案例
    • 一坨坨代码实现
    • 有何问题
  • 二、命令模式讲解
    • 结构图及说明
    • 示例代码
    • 使用命令模式重构案例
    • 克服的问题
  • 三、回顾与展望
    • 优点
    • 缺点
    • 应用场景
    • 未来展望

一、传统实现方式

场景案例

一个经典的案例场景是“远程遥控器”(Remote Control)的设计。在这个场景中,我们可以将遥控器上的每个按钮看作是一个命令对象,而遥控器本身则是一个命令的调用者。当用户按下遥控器上的某个按钮时,遥控器就会调用相应的命令对象来执行操作。

一坨坨代码实现

    一个简单的、直接的实现方法可能是直接在遥控器类中为每一个可能的动作定义一个方法。当一个按钮被按下时,就直接调用对应的方法。这种做法会使得遥控器类和实际执行动作的类高度耦合,因为遥控器类需要知道所有可能的动作以及如何执行这些动作。

// 遥控器调用者
class RemoteControl {private Light light;private Television television;public RemoteControl(Light light, Television television) {this.light = light;this.television = television;}public void pressButton(String button) {switch(button) {case "lightOn":light.turnOn();break;case "lightOff":light.turnOff();break;case "tvOn":television.turnOn();break;case "tvOff":television.turnOff();break;case "volumeUp":television.volumeUp();break;case "volumeDown":television.volumeDown();break;// 更多可能的按钮动作...default:System.out.println("Button " + button + " not mapped to an action.");break;}}
}// 灯光类
class Light {public void turnOn() {System.out.println("Light is On.");}public void turnOff() {System.out.println("Light is Off.");}
}// 电视类
class Television {public void turnOn() {System.out.println("Television is On.");}public void turnOff() {System.out.println("Television is Off.");}public void volumeUp() {System.out.println("Television volume turned up.");}public void volumeDown() {System.out.println("Television volume turned down.");}
}// 客户端代码
class Demo {public static void main(String[] args) {Light light = new Light();Television tv = new Television();RemoteControl remote = new RemoteControl(light, tv);remote.pressButton("lightOn");remote.pressButton("tvOn");remote.pressButton("volumeUp");// ... 更多动作}
}

    请注意,虽然这种方法可以实现功能,但它违反了设计原则,如开闭原则(OCP)和单一职责原则(SRP)。每新增一个设备或者一个功能,都需要修改RemoteControl类的代码,这使得RemoteControl类随着时间推进和功能增加变得越来越庞大和难以维护。

有何问题

    上述实现设计存在以下问题:

 1. 高耦合: 遥控器类(RemoteControl)直接依赖于特定的设备类(如Light和Television),并且需要知道它们的接口和实现细节。这违背了设计模式中强调的依赖倒置原则,即高层模块不应该依赖于底层模块,它们都应该依赖于抽象。

 2. 违反开闭原则 (OCP): 如果需要添加新的设备或者动作,例如让遥控器控制空调,就必须修改RemoteControl类的pressButton方法,添加新的case分支。开闭原则指出软件实体应该对扩展开放,对修改关闭。上述设计并不满足这一原则。

 3. 违反单一职责原则 (SRP): RemoteControl类不仅是调用者,还决定了逻辑如何执行。这给了RemoteControl多个变化的原因,比如设备接口改变或者控制逻辑改变。

 4. 可维护性差: 随着功能的增多,pressButton方法会变得越来越长,充满了各种case语句,这会让代码难以维护。

 5. 可扩展性差: 向遥控器中添加新功能变得复杂,需要修改现有代码并有可能引入新的错误。

 6. 重复代码: 如果多个按钮需要执行类似的逻辑,这就可能产生代码重复。

    综上所述,遥控器的这种设计缺乏灵活性和可维护性。使用命令模式可以解决这些缺点,因为命令模式将请求封装成对象,与执行操作的对象解耦,增加新命令无需修改已有的代码,只需定义新的命令对象。这样增强了代码的可维护性、扩展性,且令代码更加清晰。

二、命令模式讲解

    解决上述问题的方法是使用命令模式。

    命令模式的定义

将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。

    核心思想

将请求或操作封装成对象,并通过调用这些对象来执行操作,从而实现了客户端和接收者的解耦。

结构图及说明

在这里插入图片描述
    说明

  • 命令接口(Command Interface):这是一个抽象接口,定义了执行命令的通用方法。具体的命令类需要实现这个接口。
  • 具体命令类(Concrete Command Classes):这些类实现了命令接口,并封装了具体的操作或请求。它们通常持有一个对接收者的引用,并实现了在调用时执行相应操作的方法。
  • 接收者(Receiver):接收者对象知道如何执行与命令相关的操作。具体命令类在调用时会与接收者对象交互,执行相应的操作。
  • 调用者(Invoker):调用者对象负责调用命令对象。它通常持有一个或多个命令对象的引用,并提供一个方法来执行这些命令。调用者不需要知道命令的具体实现细节,只需要调用命令对象的方法即可。
  • 客户端(Client):客户端创建具体的命令对象,并将其传递给调用者对象。客户端还可以设置接收者对象,并将其传递给命令对象。客户端通过调用调用者的方法来间接执行命令。

    命令模式的结构允许将请求或操作封装成独立的对象,从而实现了请求调用者和请求接收者之间的解耦。这种设计模式使得请求可以被排队、撤销、重做以及事务处理等,提高了系统的灵活性和可扩展性。同时,通过引入命令接口和具体命令类,也使得新的命令可以很容易地加入到系统中,而无需修改现有的代码。

示例代码

    首先,我们需要定义一个Command接口,所有的具体命令类都需要实现这个接口:

public interface Command {  void execute();  
}

    接下来,我们定义两个具体的命令类ConcreteCommandA和ConcreteCommandB,它们实现了Command接口:

public class ConcreteCommandA implements Command {  private Receiver receiver;  public ConcreteCommandA(Receiver receiver) {  this.receiver = receiver;  }  @Override  public void execute() {  receiver.action();  }  
}  public class ConcreteCommandB implements Command {  private Receiver receiver;  public ConcreteCommandB(Receiver receiver) {  this.receiver = receiver;  }  @Override  public void execute() {  receiver.anotherAction();  }  
}

    然后,我们需要定义一个Receiver类,这个类将执行实际的操作:

public class Receiver {  public void action() {  System.out.println("Executing action in Receiver");  }  public void anotherAction() {  System.out.println("Executing another action in Receiver");  }  
}

    接下来,我们定义一个Invoker类,这个类将负责调用命令:

public class Invoker {  private Command command;  public Invoker(Command command) {  this.command = command;  }  public void setCommand(Command command) {  this.command = command;  }  public void executeCommand() {  command.execute();  }  
}

    最后,我们可以在客户端代码中使用这些类:

public class Client {  public static void main(String[] args) {  Receiver receiver = new Receiver();  Command commandA = new ConcreteCommandA(receiver);  Command commandB = new ConcreteCommandB(receiver);  Invoker invoker = new Invoker(commandA);  invoker.executeCommand();  // 输出 "Executing action in Receiver"  invoker.setCommand(commandB);  invoker.executeCommand();  // 输出 "Executing another action in Receiver"  }  
}

    在这个示例中,Command接口定义了一个execute方法,ConcreteCommandA和ConcreteCommandB类实现了这个接口,并在execute方法中调用了Receiver对象的不同方法。Invoker类持有一个Command对象,并提供了executeCommand方法来执行命令。在客户端代码中,我们创建了一个Receiver对象和两个命令对象,并使用Invoker对象来执行这些命令。

使用命令模式重构案例

    假设原有的实现中包含的是一个简单的遥控器类RemoteControl,用于控制Light(开/关灯)和Television(开/关电视)两种设备。我们将使用命令模式实现它,首先定义命令接口,然后创建几个具体的命令类,之后实现调用者即遥控器类,最后实现接收者类。

  1. 定义命令接口 (Command):
public interface Command {void execute();
}
  1. 实现具体命令类 (ConcreteCommands):
// Light On Command
public class LightOnCommand implements Command {private Light light;public LightOnCommand(Light light) {this.light = light;}public void execute() {light.on();}
}// Light Off Command
public class LightOffCommand implements Command {private Light light;public LightOffCommand(Light light) {this.light = light;}public void execute() {light.off();}
}// Television On Command
public class TelevisionOnCommand implements Command {private Television television;public TelevisionOnCommand(Television television) {this.television = television;}public void execute() {television.on();}
}// Television Off Command
public class TelevisionOffCommand implements Command {private Television television;public TelevisionOffCommand(Television television) {this.television = television;}public void execute() {television.off();}
}
  1. 实现调用者 (Invoker):
public class RemoteControl {private Command[] onCommands;private Command[] offCommands;public RemoteControl() {onCommands = new Command[2];offCommands = new Command[2];}public void setCommand(int slot, Command onCommand, Command offCommand) {onCommands[slot] = onCommand;offCommands[slot] = offCommand;}public void pressOnButton(int slot) {onCommands[slot].execute();}public void pressOffButton(int slot) {offCommands[slot].execute();}
}
  1. 实现接收者 (Receivers):
// Light class
public class Light {public void on() {System.out.println("Light is on.");}public void off() {System.out.println("Light is off.");}
}// Television class
public class Television {public void on() {System.out.println("Television is on.");}public void off() {System.out.println("Television is off.");}
}
  1. 使用命令模式
public class Client {public static void main(String[] args) {RemoteControl remote = new RemoteControl();Light light = new Light();Television tv = new Television();Command lightOn = new LightOnCommand(light);Command lightOff = new LightOffCommand(light);Command tvOn = new TelevisionOnCommand(tv);Command tvOff = new TelevisionOffCommand(tv);remote.setCommand(0, lightOn, lightOff);remote.setCommand(1, tvOn, tvOff);// Turn on the light and tvremote.pressOnButton(0);remote.pressOnButton(1);// Turn off the light and tvremote.pressOffButton(0);remote.pressOffButton(1);}
}

    这样,我们使用命令模式实现了遥控器类。添加新命令只需创建新的Command类,然后使用setCommand方法将其设为特定按钮的操作。无需修改远程控制器的内部逻辑,符合开闭原则。

克服的问题

    使用命令模式实现遥控器场景能够解决的问题包括:

 1. 高耦合: 在不使用命令模式的情况下,遥控器需要直接调用具体设备的操作方法,这造成了调用者和接收者之间的高耦合。使用命令模式后,遥控器只需要知道如何触发命令对象,而具体的设备操作被封装在命令对象中,降低了耦合性。

 2. 开闭原则 (OCP): 开闭原则强调系统设计应该对扩展开放,对修改封闭。在命令模式中,若要引入新的命令或动作,无需修改遥控器的代码,只需要创建新的命令对象即可。这样遥控器的功能扩展不需要修改既有代码,保持了系统的开放性与封闭性。

 3. 单一职责原则 (SRP): 单一职责原则要求一个类应该只有一个引起变化的原因。在命令模式中,遥控器的职责仅限于发出请求,而命令对象负责定义具体的操作行为,这样就将两者的责任区分开来,满足了SRP。

 4. 可维护性: 在没有命令模式的遥控器实现中,交织的命令逻辑使得代码难以理解和维护。命令模式将命令逻辑封装在单独的对象中,使得遥控器和设备的代码更加清晰,提高了可维护性。

 5. 可扩展性: 不使用命令模式,每增加一个操作或设备都可能需要修改遥控器的代码。命令模式使得增加新的命令或设备变得容易,只需定义新的命令类,无需改动遥控器或其他命令类。

 6. 代码复用: 没有命令模式的遥控器实现可能会导致很多重复代码,比如多个类似设备的操作可能非常相似。命令模式提高代码复用性,因为可以通过继承或组合来复用命令类代码,从而减少重复。

    命令模式通过对命令的抽象和封装提供了一种清晰而灵活的方式来解耦调用者和接收者,使代码变得更加模块化,易于理解、维护和扩展。

三、回顾与展望

优点

  • 解耦发送者和接收者:命令模式将发起请求的对象(发送者)和执行请求的对象(接收者)分离开来。这样,发送者只需要知道如何发送请求,而不需要知道请求的具体实现细节,从而降低了系统的耦合度。
  • 扩展性:当需要引入新命令时,不需要改变现有的代码,只需增加新的命令类。这符合开闭原则,对于扩展是开放的,对于修改是封闭的。
  • 重用性:你可以重用这些命令,因为命令本身与其操作的上下文是独立的。
  • 灵活性:命令模式可以支持撤销(undo)和重做(redo)操作,因为每个命令都能够记录它的历史状态,或者可以提供撤销其所做操作的方式。
  • 可以将一组简单的命令组合成复杂的命令。
  • 可以方便地实现请求的记录和队列化。

缺点

  • 类膨胀:对于每一个操作都需要创建一个特定的命令类,随着应用程序命令增多,会产生大量类,使系统变得更加复杂。
  • 增加复杂性:对于简单的操作,使用命令模式可能会过于复杂,它会引入许多额外的类和对象,增加了系统的复杂度。
  • 性能考虑:如果在某些性能敏感的系统中,增加这样一个额外的抽象层可能会影响性能。

    命令模式在需要将发起操作和执行操作解耦时表现很好,在菜单选择、队列请求、事务操作以及作业排队等场景下特别有用。然而,适当的使用是关键,因为在不需要这种级别灵活性的简单场景中,它可能会导致不必要的复杂性。

应用场景

    命令模式作为一种行为设计模式,是处理请求和操作执行解耦的强大工具。以下是命令模式的一些典型应用场景:

  • GUI按钮和菜单操作:图形用户界面(GUI)程序中,按钮行为和菜单命令通常使用命令模式实现。每个按钮或菜单项都有不同的行为和请求,命令模式允许将这些行为封装成具体的命令对象,使得你可以根据需要动态地为按钮分配不同的功能。
  • 撤销/重做功能:在文本编辑器、图像编辑软件或数据库事务管理等应用程序里实现撤销(Undo)和重做(Redo)功能。命令对象可以用来记录发生的行为及其状态,可以在必要时回滚或重播这些行为。
  • 操作队列:在需要排队多个请求并按顺序执行它们的场景中,如线程池、任务管理器或后台作业调度。命令模式可以将所有的请求封装成命令对象并添加到队列中,独立于请求本身。
  • 日志请求:在需要记录和存储用户操作的系统中,可以使用命令模式记录每个操作的详细信息,当系统崩溃或出错时能够通过日志重放用户的操作以恢复到之前的状态。
  • 智能家居或物联网(IoT)控制:智能家居应用中将用户的操作(如打开灯光、设置温度等)抽象为命令,这些命令可以远程或定时执行,命令模式使得新增更多功能(如新的设备控制)变得简单。
  • 异步任务执行:在需要将请求处理的工作委托给后台线程执行的系统中,可以将这些请求作为命令放入工作队列中,由后台服务进行处理。
  • 事务行为管理:在需要实现事务的系统中(比如需要保证一系列操作要么全部成功要么全部失败),命令对象能够用于封装所有事务的操作,并在发生错误时进行回滚。

未来展望

    随着软件设计的不断进步,命令模式作为一种行为设计模式,其在分离命令的定义与调用、组织复杂命令结构等方面的优势将会保持其重要性。未来的发展趋势和可能的应用方向可从以下几个方面进行探讨:
    与新兴技术的融合
    命令模式很可能会与当前逐渐普及的技术像云计算、物联网(IoT)以及人工智能(AI)产生更紧密的结合。例如,在智能家居领域,命令模式可以用来设计一个集中的控制系统,用以发送和调度对各种家电的控制命令;在云服务中,命令模式可以协助构建更为灵活的服务调用机制,促进分布式系统的命令传递和执行。

    可扩展性与微服务架构
    随着微服务架构的流行,命令模式的可扩展性将得到进一步重视。微服务架构依赖于服务的精细化管理和交互,而利用命令模式能够有效地对服务间传递的命令进行封装处理,使得服务间的通信更加的稳定与易于维护。

    丰富的行为组合与软件自动化
    命令模式也可以在增强软件自动化方面发挥重要作用。由于它支持撤销、重做等操作,这使得自动化脚本或框架在执行过程中可以更灵活地控制事务。同时,命令的组合能力可以促使开发者创造出更加复杂和智能化的宏命令,这些宏命令可以应对快速变化的业务逻辑和工作流程。

    增强人机交互体验
    随着VR(虚拟现实)、AR(增强现实)等交互技术的发展,命令模式有潜力在未来的人机交互系统中扮演关键角色。在这些系统中,用户的各种指令可以通过命令模式进行封装,从而提供更为直观和流畅的交互体验。

    面向可持续发展的软件设计
    环境和可持续发展成为全球关注的热点,软件设计同样需要考虑绿色计算。命令模式由于其高度解耦命令发起者与执行者的特性,有助于构建能够轻松适应能效优化和资源管理策略的软件系统。

结语
    命令模式,作为一种成熟和灵活的设计模式,对于软件工程师来说是必不可少的工具之一。随着科技的发展和计算模型的演变,命令模式的应用场景将会越发广泛,其在设计模式中的地位也将日益凸显。
    继续深入学习和实践命令模式。务求不仅理解其基本概念和结构,还要通过实际项目练习来把握其精髓,灵活运用到各种复杂场景中。不断探索命令模式与其他设计模式的结合使用,也是拓宽设计思路、提升软件质量的重要途径。
    记住,技术总是在变,但设计模式提供的是解决问题的思想和方法。持续学习,不断实践,让我们一同推动软件设计的边界向前延伸。

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

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

相关文章

12.QT文件对话框 文件的弹窗选择-QFileDialog

目录 前言: 技能: 内容: 1. 界面 2.信号槽 3.其他函数 参考: 前言: 通过按钮实现文件弹窗选择以及关联的操作 效果图就和平时用电脑弹出的选文件对话框一样 技能: QString filename QFileDialog::ge…

MATLAB | 绘图复刻(十五) | 环形聚类树状图

本期复刻效果: 感觉出的聚类分析树状图绘制工具也不少了,未来可能会统一整理为一个工具包?(任重道远,道阻且长): 代码讲解 0 数据设置 写了比较多的注释应该比较易懂: clc; clear; close all% 样品起名s…

Linux------环境变量

目录 前言 一、环境变量 二、添加PATH环境变量 三、HOME环境变量 四、查看所有环境变量 1.指令获取 2.代码获取 2.1 getenv 2.2main函数的第三个参数 2.3 全局变量environ 五、环境变量存放地点 六、添加自命名环境变量 七、系统环境变量具有全局属性 八、环境变…

芋道---实现可退回至申请人节点(附完整代码)

现有如下需求,审批人在退回申请时,想退回至申请人节点,但目前芋道并不支持退回至申请人节点,现做如下修改,实现该需求: 步骤一:设计流程模型 首先,我们在设计流程模型时&#xff0c…

0205-2-数据链路层

第 3 章 数据链路层 使用点对点信道的数据链路层 数据链路和帧 数据链路层使用的信道主要有以下两种类型: 点对点信道。这种信道使用一对一的点对点通信方式。广播信道。这种信道使用一对多的广播通信方式,因此过程比较复杂。广播信道上连接的主机很多…

Linux——网络通信TCP通信常用的接口和tcp服务demo

文章目录 TCP通信所需要的套接字socket()bind()listen()acceptconnect() 封装TCP socket TCP通信所需要的套接字 socket() socket()函数主要作用是返回一个描述符,他的作用就是打开一个网络通讯端口,返回的这个描述符其实就可以理解为一个文件描述符&a…

c高级 函数+Makefile

一、作业 1.写一个函数,输出当前用户的uid和gid,并使用变量接收结果 #!/bin/bash function fun(){retid -uret1id -gecho $ret $ret1 } retfun echo $ret二、练习回顾 1.分文件编译(实现冒泡排序) 正确的:将数组的…

HTTP/1.1 如何优化?

问你一句:「你知道 HTTP/1.1 该如何优化吗?」 我们可以从下面这三种优化思路来优化 HTTP/1.1 协议: 尽量避免发送 HTTP 请求在需要发送 HTTP 请求时,考虑如何减少请求次数减少服务器的 HTTP 响应的数据大小 下面,就针对这三种思路具体看看有哪些优化…

【Java EE初阶十六】网络原理(一)

在网络原理中主要学习TCP/IP四层模型中的重点网络协议 1. 应用层 1.1 应用程序与协议 应用层是和程序员接触最密切的; 应用程序:在应用层这里,很多时候都是程序员自定义应用层协议(步骤:1、根据需求,明确…

log4net的使用步骤

log4net的使用步骤 Log4net是一个基于.NET平台的开源日志记录组件,它可以帮助开发人员在应用程序中添加日志记录功能,支持多种日志级别,如DEBUG、INFO、WARN、ERROR等,这使得开发人员可以根据需要灵活地控制日志的输出。下面是lo…

SPSSAU【文本分析】|我的词库

我的词库 文本分析时,可能涉及到一些新词,比如‘内卷’,这个词很可能在词典中并未出现过,词库也不认识它。但研究者自己认识它,此时可将该词纳入到新词词库中,让系统统计词频等信息时也对该词进行统计。当…

【监控】spring actuator源码速读

目录 1.前言 2.先搂一眼EndPoint 3.EndPoint如何被注入 4.EndPoint如何被暴露 4.1.如何通过http暴露 4.2.如何通过jmx暴露 5.EndPoint是怎么实现监控能力的 6.知道这些的意义是什么 1.前言 版本:spring-boot-starter-actuator 2.6.3 阅读源码一定要带着疑…

小迪安全26WEB 攻防-通用漏洞SQL 注入 SqlmapOracleMongodbDB2 等

#知识点: 1、数据库注入-Oracle&Mongodb 2、数据库注入-DB2&SQLite&Sybase 3、SQL 注入神器-SQLMAP 安装使用拓展 数据库注入: 数据库注入-联合猜解-Oracle&Mongodb 1.Oracle数据库一般会在java上执行 参考:https://www.cnblog…

图数据库 之 Neo4j - 应用场景1(6)

Neo4j是一种图数据库,它专注于处理关系数据密集型的问题。由于其图结构的特性,Neo4j能够高效地存储、查询和分析连接数据。 以下是一些常见的Neo4j应用场景: 社交网络分析:通过建模和分析人际关系,可以揭示社交网络中…

【详解】图的概念和存储结构(邻接矩阵,邻接表)

目录 图的基本概念: 图的存储结构 邻接矩阵(GraphByMatrix): 基本参数: 初始化: 获取顶点元素在其数组中的下标 : 添加边和权重: 获取顶点的度: 打印图&#xf…

Unity所有关于旋转的方法详解

前言:欧拉角和四元数的简单描述 我们在Inspector面板上看到的rotation其实是欧拉角, 我们将Inspector面板设置成Debug模式,此时看到的local Rotation才是四元数。 Unity中的欧拉旋转是按照Z-X-Y顺规执行的旋转,一组欧拉旋转过程中…

[力扣 Hot100]Day29 删除链表的倒数第 N 个结点

题目描述 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 出处 思路 两个指针间隔n,一趟遍历解决。 代码 class Solution { public:ListNode* removeNthFromEnd(ListNode* head, int n) {ListNode* phead;ListNode* …

【数据库】Mysql索引

1、什么是索引?为什么要用索引? 1.1、索引的含义 数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询,更新数据库中表的数据。索引的实现通常使用B树和变种的B树(MySQL常用的索引就是B树&am…

跟着pink老师前端入门教程(JavaScript)-day03

四、常量 概念:使用 const 声明的变量称为“常量”。 使用场景:当某个变量永远不会改变的时候,就可以使用 const 来声明,而不是let。 命名规范:和变量一致 常量使用: 注意:常量不允许重新…

数据库索引面试的相关问题

查看索引的执行计划 索引失效的情况 1、索引列上做了计算,函数,类型转换等操作。索引失效是因为查询过程需要扫描整个索引并回表。代价高于直接全表扫描。 Like匹配使用了前缀匹配符“%abc” 字符串不加引号导致类型转换。 原因: 常见索…