命令模式(Command Pattern)
- 格式:doc
- 大小:238.50 KB
- 文档页数:12
软件开发中的设计模式有哪些在软件开发的领域中,设计模式就像是一套经过实践检验的解决方案,帮助开发者更高效、更优雅地解决常见的问题。
它们是软件开发中的宝贵经验总结,为构建可维护、可扩展和灵活的软件系统提供了有力的支持。
接下来,让我们一起探索一下软件开发中常见的设计模式。
一、创建型设计模式1、单例模式(Singleton Pattern)单例模式确保一个类只有一个实例存在,并提供一个全局访问点来获取该实例。
这在某些情况下非常有用,比如一个系统中只需要一个数据库连接池或者一个日志记录器。
想象一下,如果多个线程同时创建多个数据库连接池实例,不仅会浪费资源,还可能导致混乱。
通过单例模式,我们可以保证只有一个实例存在,有效地管理资源。
2、工厂模式(Factory Pattern)当我们需要创建对象,但又不想让客户端直接与具体的类进行交互时,工厂模式就派上用场了。
它定义了一个用于创建对象的接口,让子类决定实例化哪一个类。
比如,在一个汽车生产厂中,有不同类型的汽车(轿车、SUV 等),我们可以通过一个工厂类根据需求来创建相应类型的汽车对象,而客户端只需要向工厂请求即可,无需关心具体的创建细节。
3、抽象工厂模式(Abstract Factory Pattern)抽象工厂模式提供了一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
例如,一个家具厂可能生产多种风格的家具(现代风格、古典风格),每种风格都有配套的椅子、桌子和沙发。
通过抽象工厂模式,我们可以根据用户选择的风格创建一整套家具,保证了风格的一致性和协调性。
4、建造者模式(Builder Pattern)建造者模式将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
比如构建一个电脑配置,我们可以有不同的 CPU、内存、硬盘等组件选择,通过建造者模式,可以清晰地定义构建的步骤和顺序,同时能够灵活地组合不同的组件来创建出各种不同配置的电脑。
Vi操作说明一. 模式说明1.两种模式:Command mode(命令模式):用于输入命令。
Insert mode(插入模式):用于插入文本。
2.模式之间的切换:二. 操作说明1.文档的操作1)打开文档:vi fn…fn 打开或创建文档(多个文档时候用 :n 切换到下一个文档)。
vi +n | + fn 打开文档件并置光标于第n行或最后一行。
vi +/pattern fn 打开文档并置光标于第一个与pattern匹配的字串处。
2)保存文档::w 保存当前文档:w! 强制保存3)退出文档::q 退出vi (文档如果有更改会提示是否保存):q! 不保存文件并退出:x 保存文件并退出4)恢复文档:vi –r fn 恢复文档fn 至上次正在编辑时的系统崩溃点。
5)删除文档:rm fn … fn 删除文档fn或多个6)重命名文档:mv fn_old fn_new 用fn_new重命名文档fn_old7)拷贝文档:cp ../fn_sou ../fn_des 拷贝文档fn_sou至 fn_des,文档可以指定定绝对路径或相对路径2.文本的操作及编辑命令1)光标移动:h,j,k,l 左,下,上,右移一个字符b | B ,w | W 左,右移一个字至字首e | E 右移一个字至字首) | ( , } | { 句尾|句首,段尾|段首n+ | n- | nG 下移n行|上移n行|移至第n行行首G 移至文档尾行0 | $ 移至光标所在行首|行尾H | M | L 移至屏幕顶|中|尾行行首ctrl+u | ctrl+d 向文档首|尾翻半屏ctrl+f | ctrl+b 向文档首|尾翻一屏2)插入命令:i | I 在光标前插入|在当前行首插入a | A 在光标后插入|在当前行首插入o | O 在当前行之下|之上新增加一行r | R 替换当前字符|替换当前字符及其后的字符至按ESC键ns | nS 光标所在位置开始以输入文本代替指定数目的字符|行ncw | ncW 修改指定数目的字ncc 修改指定数目的行u 撤销修改或删除3)删除命令:nx | nX 删除光标处字符及其后 | 前的n-1个字符ndw | ndW 删除光标处开始及其后的n-1个字d0 | d$ 删除至行首|尾ndd 删除当前行及其后的n-1行: n1,n2 d 将n1行到n2行之间的内容删除4)搜索命令:/pattern | ?pattern 从光标处开始向文档尾 | 首部搜索patternn | N 在同 | 反向上重复上一次搜索命令5)替换命令::n1,n2s/p1/p2/g 将第n1行至第n2行中所有的p1用p2代替注:A. 其中n1,n2的几种特殊情况a.可以不指定,如::s/p1/p2/g 将当前行中所有p1替换成p2b.可以只指定n2,如: :,n2s/p1/p2/g 将当前行至第n2行中所有p1替换成p2c.特殊范围: :0,$s/p1/p2/g 将首行至尾行中所有p1替换成p2其中 0,$ 可以换成 %。
安卓常⽤的6种设计模式总结最近看到两篇博客,觉得很不错,记录⼀下由于项⽬变更的频繁性,作为⼀名程序员,我们需要掌握设计模式的必要性,就不⾔⽽喻~~,下⾯就是⼀些我⾃⼰学习的设计模式总结。
接下来,主要是针对⼏个⽐较常⽤模式进⾏讲解,主要是以下⼏种:观察者模式适配器模式代理模式⼯⼚模式单例模式命令模式1.观察者模式(Observer Pattern)释义:观察者模式定义了⼀种⼀对多的依赖关系,让多个观察者对象同时监听某⼀个主题对象,这个主题对象在状态上发⽣变化时,会通知所有观察者对象,使他们能够⾃动更新⾃⼰。
故事理解:观察者想知道公司所有MM的情况,只要加⼊公司的MM情报邮件组就⾏了,tom负责搜集情报,当发现新情报时,不⽤⼀个⼀个通知我们,直接发布给邮件组,我们作为订阅者(观察者)就可以及时收到情报啦。
常见实例:1.BaseAdapter.registerDataSetObserver和BaseAdapter.unregisterDataSetObserver两⽅法来向BaseAdater注册、注销⼀个DataSetObserver ; 2.使⽤ContentObserver去监听数据库变化。
适⽤场景:1.当对⼀个对象的改变需要同时改变其他对象,⽽不知道具体有多少对象有待改变;2.当⼀个对象必须通知其它对象,⽽它⼜不能假定其它对象是谁.观察者模式主要有观察者和被观察者2个对象,在该模式中,Observable表⽰被观察者,这个对象是⼀个抽象类,只能被继承。
Observer表⽰观察者,他是⼀个接⼝,所以观察者可以有多个,实现了该接⼝的类都是属于观察者。
这是⽹上⼀个⽣动细致的demo:被观察者:public class MyPerson extends Observable {private int age;private String name;private String sax;public int getAge() {return age;}public void setAge(int age) {this.age = age;setChanged();notifyObservers();}public String getName() {return name;}public void setName(String name) { = name;setChanged();notifyObservers();}public String getSax() {return sax;}public void setSax(String sax) {this.sax = sax;}@Overridepublic String toString() {return "MyPerson [age=" + age + ", name=" + name + ", sax=" + sax + "]";}}MyPerson是被观察者,类中调⽤了setChange()以及notifyObservers()两个⽅法,前者是告知数据改变,后者是发送信号通知观察者。
命令模式将请求封装成对象使得可以用不同的请求对客户进行参数化命令模式(Command Pattern)是一种行为设计模式,它将一个请求封装成一个对象,使得可以用不同的请求对客户进行参数化。
这种模式中,请求的调用者和请求的接收者解耦,使得调用者不需要知道请求的接收者的具体信息。
在实际的软件开发中,命令模式是一个非常常用的设计模式。
它可以用于实现菜单项的点击事件、处理用户交互的命令、撤销和重做操作等功能。
下面我们通过一个简单的例子来说明命令模式的使用场景和优势。
假设我们正在开发一个家庭智能控制系统,用户可以通过手机APP 控制家里的电器设备。
现在我们要实现一个功能,当用户点击“开灯”按钮时,系统能够自动打开客厅的灯。
这个功能可以通过命令模式来实现。
首先,我们定义一个抽象命令类(Command),其中包含一个抽象方法execute()用于执行命令。
接下来,我们定义具体的命令类(LightOnCommand),继承自抽象命令类,实现execute()方法,在execute()方法中调用相应的接收者(Light)的方法,完成具体的操作(打开灯)。
同时,我们还需要定义一个接收者类(Light),其中包含打开灯的方法。
接下来,我们可以定义一个请求者(Invoker)类,该类包含一个命令对象(Command)作为成员变量,并提供一个方法用于设置命令对象。
在请求者类的方法中,调用命令对象的execute()方法实现请求的执行。
最后,我们可以编写一个客户端类(Client),通过该类来测试命令模式的使用。
在客户端类中,我们实例化命令对象和接收者对象,将命令对象设置进请求者对象,然后调用请求者对象的方法。
这样,当用户点击“开灯”按钮时,请求者对象会调用命令对象的execute()方法,从而执行相应的命令,打开客厅的灯。
通过使用命令模式,我们可以很方便地实现对请求的封装和参数化。
比如,如果用户点击“关灯”按钮,我们只需要定义一个新的具体命令类(LightOffCommand),实现execute()方法即可。
java命令模式举例命令模式(Command Pattern)是一种行为型设计模式,它将请求封装成对象,以便可以参数化请求对象并将其排队、传递、执行或取消。
命令模式允许您将请求的发送者和接收者解耦,并支持撤销操作。
以下是一个简单的Java命令模式的示例,以控制电视的开关操作。
首先,定义一个命令接口`Command`,它包含一个执行方法`execute()`:```javainterface Command {void execute();}```然后,创建具体命令类,如`TurnOnCommand` 和`TurnOffCommand`,它们实现了`Command` 接口,用于执行开启和关闭电视的操作:```javaclass TurnOnCommand implements Command {private Television television;public TurnOnCommand(Television television) {this.television = television;}@Overridepublic void execute() {television.turnOn();}}class TurnOffCommand implements Command {private Television television;public TurnOffCommand(Television television) {this.television = television;}@Overridepublic void execute() {television.turnOff();}}接下来,创建接收者类`Television`,它包含了具体的操作:```javaclass Television {public void turnOn() {System.out.println("Television is turned on");}public void turnOff() {System.out.println("Television is turned off");}}```然后,创建一个遥控器类`RemoteControl`,它包含了执行命令的方法和一些按钮,可以将命令绑定到这些按钮上:```javaclass RemoteControl {private Command onCommand;private Command offCommand;public void setOnCommand(Command onCommand) {this.onCommand = onCommand;}public void setOffCommand(Command offCommand) {this.offCommand = offCommand;}public void turnOnTelevision() {onCommand.execute();}public void turnOffTelevision() {offCommand.execute();}}```最后,在客户端代码中,您可以创建遥控器、命令和电视,并将命令绑定到遥控器按钮上,然后执行命令:```javapublic class Main {public static void main(String[] args) {Television television = new Television();Command turnOn = new TurnOnCommand(television);Command turnOff = new TurnOffCommand(television);RemoteControl remoteControl = new RemoteControl();remoteControl.setOnCommand(turnOn);remoteControl.setOffCommand(turnOff);remoteControl.turnOnTelevision();remoteControl.turnOffTelevision();}}```在这个示例中,命令模式允许您将开启和关闭电视的操作封装为命令对象,并将这些命令与遥控器按钮绑定。
命令模式与观察者模式:解耦与扩展代码的设计模式命令模式和观察者模式是两种常见的设计模式,它们可以帮助我们解耦和扩展代码。
下面我将详细介绍这两种模式,并分析它们的优点和适用场景。
1.命令模式(Command Pattern)命令模式是一种行为型设计模式,它将请求封装成一个对象,从而使得我们可以用不同的请求来参数化其他对象。
命令模式的核心思想是将方法调用、请求或者操作封装到一个单一的对象中,然后通过传递和调用这个对象来实现请求的不同。
命令模式的主要角色包括:-命令接口(Command Interface):用于封装请求的接口,通常包含一个执行(execute)方法。
-具体命令类(Concrete Command Class):实现命令接口,负责执行具体的操作。
-命令接收者(Command Receiver):负责执行命令的对象。
-命令发起者(Command Invoker):负责调用命令对象执行请求。
命令模式的优点有:-解耦:命令模式可以将命令的接收者和发送者解耦,发送者只需要知道如何调用命令对象,而无需知道命令对象如何处理请求。
-扩展:通过添加新的命令对象,可以很方便地扩展和改变系统的行为。
-撤销和重做:命令模式可以支持撤销和重做操作,通过保存命令对象的历史记录,可以回到之前的状态。
命令模式适用的场景有:-需要将命令的请求者和执行者解耦时,可以使用命令模式。
-需要支持撤销和重做操作时,可以使用命令模式。
-需要记录操作日志时,可以使用命令模式。
2.观察者模式(Observer Pattern)观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生变化时,它的所有依赖者都会收到通知并作出相应的更新。
观察者模式的核心思想是将观察者和被观察者解耦,使得它们可以独立地变化。
观察者模式的主要角色包括:-被观察者(Subject):维护一组观察者对象,并提供添加、删除和通知观察者的接口。
vi编辑器:命令模式、输⼊模式、末⾏模式1、命令模式(command mode)—执⾏命令 在该模式中,可以输⼊命令来执⾏许多种功能。
控制屏幕光标的移动,字符、字或⾏的删除,移动复制某区段及进⼊Insert mode下,或者到last line mode。
2、输⼊模式(Insert mode)—输⼊⽂本 vi被运⾏时,通常处在命令模式下,键⼊以下命令可以使vi退出命令模式,进⼊输⼊模式:I(i)、A(a)、O(o)。
3、末⾏模式(last line mode)—执⾏待定命令 将⽂件保存或退出vi,也可以设置编辑环境,如寻找字符串、列出⾏号……等。
不过⼀般我们在使⽤时把vi简化成两个模式,就是将末⾏模式(last line mode)也算⼊命令⾏模式command mode)。
1. vi的启动 输⼊vi命令后,便进⼊全屏幕编辑环境,此时的状态为命令模式。
(1) vi 进⼊vi的⼀个临时缓冲区,光标定位在该缓冲区第1⾏第1列的位置上。
(2) vi file1 如果file1⽂件不存在,将建⽴此⽂件;如该⽂件存在,则将其拷贝到⼀个临时缓冲区。
光标定位在该缓冲区第1⾏第1列的位置上。
(3) vi + file1 如果file1⽂件不存在,将建⽴此⽂件;如该⽂件存在,则将其拷贝到⼀个临时缓冲区。
光标定位在⽂件最后1⾏第1列的位置上。
(4) vi +N file1(N:为数字) 如果file1⽂件不存在,将建⽴此⽂件;如该⽂件存在,则将其拷贝到⼀个临时缓冲区。
光标定位在⽂件第N⾏第1列的位置上。
(5) vi +/string file1 如果file1⽂件不存在将建⽴此⽂件;如该⽂件存在则将其拷贝到⼀个临时缓冲区。
光标定位在⽂件中第⼀次出现字符串string的⾏⾸位置。
2. 退出vi(末⾏模式(last line mode)) 建议在退出vi前,先按ESC键,以确保当前vi的状态为命令⽅式,然后再键⼊“:”(冒号),输⼊下列命令,退出vi。
虚拟机编辑器vi使⽤⽅法详细介绍vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强⼤不逊⾊于任何最新的⽂本编辑器,这⾥只是简单地介绍⼀下它的⽤法和⼀⼩部分指令。
由于对Unix及Linux系统的任何版本,vi编辑器是完全相同的,因此您可以在其他任何介绍vi的地⽅进⼀步了解它。
Vi也是Linux中最基本的⽂本编辑器,学会它后,您将在Linux的世界⾥畅⾏⽆阻。
基本上vi可以分为三种状态,分别是命令模式(command mode)、插⼊模式(Insert mode)和底⾏模式(last line mode),各模式的功能区分如下:1) 命令⾏模式command mode) 控制屏幕光标的移动,字符、字或⾏的删除,移动复制某区段及进⼊Insert mode下,或者到 last line mode。
2) 插⼊模式(Insert mode) 只有在Insert mode下,才可以做⽂字输⼊,按「ESC」键可回到命令⾏模式。
3) 底⾏模式(last line mode) 将⽂件保存或退出vi,也可以设置编辑环境,如寻找字符串、列出⾏号……等。
不过⼀般我们在使⽤时把vi简化成两个模式,就是将底⾏模式(last line mode)也算⼊命令⾏模式command mode)。
在系统提⽰符号输⼊vi及⽂件名称后,就进⼊vi全屏幕编辑画⾯: $ vi myfile 不过有⼀点要特别注意,就是您进⼊vi之后,是处于「命令⾏模式(command mode)」,您要切换到「插⼊模式(Insert mode)」才能够输⼊⽂字。
初次使⽤vi的⼈都会想先⽤上下左右键移动光标,结果电脑⼀直哔哔叫,把⾃⼰⽓个半死,所以进⼊vi后,先不要乱动,转换到「插⼊模式(Insert mode)」再说吧!在「命令⾏模式(command mode)」下按⼀下字母「i」就可以进⼊「插⼊模式(Insert mode)」,这时候你就可以开始输⼊⽂字了。
描述:通常,面向对象应用程序是由一组能够提供有限的、专注于功能的相互交互的对象集合组成。
为了响应用户的交互动作,应用程序执行一系列的处理。
为了响应用户的请求,应用程序使用不同的对象提供的服务处理请求。
根据实现,应用可以指定一个对象,这个指定的对象可以调用不同对象上的操作,被称为调用者(invoker)。
(译者注:其实个人认为这个invoker在这里主动地成分更大,它是偏向于调用其他对象,这个区别就像英语employ这个动词是雇佣的意思,employee是员工??被雇佣的对象,而employer是雇主??雇佣的主动者,那么在这里的invoker是一个道理)。
调用者(invoker)可以看作为客户应用程序的一部分。
那些包含提供处理请求服务实现的对象集合成为接受对象(Receiver Object)。
Figure 30.1: Object Interaction?Before Applying the Command Pa ttern在这种设计中,发出请求的应用程序和提供处理请求服务的接受对象(Receiver Object)集合之间彼此是紧密关联的,因为它们之间直接相互交互。
这导致了在调用者(invoker)实现中会包含大量的if条件语句。
1.…2.if(RequestType=TypeA){3.//do something4.}5.6.if(RequestType=TypeB){7.//do something8.}9.…当一种新的处理类型需要加入的应用时,现存的代码需要进行修改??这违背了面向对象开放?关闭的基本原则。
1.…2.if(RequestType=TypeA){3.//do something4.}5.…6.if(RequestType=NewType){7.//do something8.}9.…使用命令模式,代表客户发布请求的调用者(invoker)和服务的处理者??接受对象(Receiver Object)之间不具有耦合性。
命令模式推荐创建一个可以为响应客户请求而执行处理或者采取动作的抽象。
指定这个抽象声明一个被其它不同的具体的实现者所实现的共同接口,这些具体的实现者称之为命令对象(Command Objects)。
每一个命令对象(Command Object)代表一种不同的客户请求和对其进行的相应处理。
在图30.2中,command接口代表了这个抽象。
它声明一个excute方法,它由两个具体的实现者(类)??ConcreteCommand_1和ConcreteCommand_2。
Figure 30.2: Command Object Hierarchy一个给定的命令对象(command Object)负责提供处理它所代表的请求的功能,但是命令对象并不包含此功能的真实实现,它是通过使用接受对象(Receiver Object)来提供处理功能。
(如图30.3)Figure 30.3: Class Association??After the Command Pattern Is Applied当客户应用程序响应用户(或者其他应用)的交互而需要提供服务时:(1)客户创建需要的接受对象(Receiver Object)。
(2)客户创建一个相应的命令对象(Command Object),并用在步骤1中创建的接受对象(Receiver Object)配置这个命令对象。
(3)客户创建一个调用者的实例(invoker), 并用在步骤2中创建的命令对象(Command Object)配置调用者。
(4)调用者调用命令对象(Command Object)上的execute方法。
(5)作为execute方法实现的一部分,特定的命令对象(Command Object)调用它所包含的接受对象上的必要方法来提供需要的服务。
在新的设计中:(1)客户/调用者(invoker)不直接与接受对象(Receiver)进行交互,它们之间完全不耦合。
(2)当应用程序需要提供新的类型的时候,可以增加一个新的命令(Command)对象。
这不需要修改调用者(invoker)的代码。
因此新的设计保证了面向对象的开放?封闭的原则。
(3)因为一个请求被指定为对象的形式,那么就存在以下可能性:1)把命令对象保存到持久介质上。
以后进行执行。
应用反向处理,实现恢复特性。
2)把不同的命令对象分组成一个独立的单元。
以下是一个FTP(File Transfer Protocol)客户事例应用程序,对于在实际应用程序中如何应用命令模式提供了很好的参考。
例子1:让我们建立一个应用程序来模拟FTP客户端的工作。
在Java 中,简单的FTP客户用户接口可以使用如下组件设计。
(1)两个JList对象用于本地和远程文件系统的显示。
(2)四个JButton对象用于初始不同的请求类型:上传、下载、删除和退出。
用户接口组件摆列在一个frame中,如图30.4Figure 30.4: Simple FTP Client UI Display每一个JButton对象创建的时候,实现了ActionListener接口的Button-Handler类的一个事例是一个ActionListener的集合。
1.public class FTPGUI extends JFrame{2.…3.…4.//Create buttons5.btnUpload = new JButton(FTPGUI.UPLOAD);6.btnUpload.setMnemonic(KeyEvent.VK_U);7.…8.…9.ButtonHandler vf = new ButtonHandler();10. btnUpload.addActionListener(vf);11. btnDownload.addActionListener(vf);12. btnDelete.addActionListener(vf);13. btnExit.addActionListener(vf);14. …15. …16.}//end of class因为这个相同的ButtonHandler实例是所有JButton对象的Action-Listener的一个集合,actionPerformed方法被所有的JButton对象调用。
因此,ButtonHandler对象必须检测哪一个按钮被按下,并执行相应的处理。
从Listing30.1中可以看到,actionPerformed方法的代码因为条件语句很不规则。
当有很多按钮和菜单对象需要添加到FTP用户界面时,actionPerformed方法的代码就很混乱。
同时,一个新的按钮对象被添加时,现在的actionPerformed 方法的代码必须修改。
这违反了面向对象的开放??关闭原则。
Listing 30.1: ButtonHandler Class1.class ButtonHandler implements ActionListener{2.public void actionPerformed(ActionEvent e) {3.//if statements - for different types of client requests4.if(e.getActionCommand().equals(FTPGUI.EXIT)) {5.System.exit(1);6.}7.if(e.getActionCommand().equals(FTPGUI.UPLOAD)) {8.int index = localList.getSelectedIndex();9.String selectedItem =10. localList.getSelectedValue().toString();11. ((DefaultListModel) localList.getModel()).remove(12. index);13. ((DefaultListModel) remoteList.getModel()).14. addElement(selectedItem);15. }16. if(e.getActionCommand().equals(FTPGUI.DOWNLOAD)) {17. int index = remoteList.getSelectedIndex();18. String selectedItem =19. remoteList.getSelectedValue().toString();20. ((DefaultListModel) remoteList.getModel()).remove(21. index);22. ((DefaultListModel) localList.getModel()).23. addElement(selectedItem);24. }25. if(e.getActionCommand().equals(FTPGUI.DELETE)) {26. int index = localList.getSelectedIndex();27. if(index >= 0) {28. ((DefaultListModel) localList.getModel()).29. remove(index);30. }31. index = remoteList.getSelectedIndex();32. if(index >= 0) {33. ((DefaultListModel) remoteList.getModel()).34. remove(index);35. }36. }37. }38.}让我们使用命令模式重新设计这个应用。
应用命令模式,我们把不同按钮对象相关联的功能抽象一个Command-face接口。
1.interface CommandInterface {2.public void processEvent();3.}不同的按钮对象可以实现这个接口,独自成为自己的命令对象。
但是,这是不推荐的,因为:(1)JButton类是一个高复用的类,在用Java Swing库创建应用用户界面的许多场合,JButton类都被使用。
实现特定的CommandInterface接口可能不是适用于所有的情况。
(2)如果JButton类实现了CommandInterface接口,它需要实现处理在用户界面(接口)上不同的JButton对象所对应的诸如上传、下载等不同请求的功能。
这会增加不相关的功能到JButton类中??导致低聚和。
另外:1)这会导致不规则的条件语句。