设计模式小结-命令模式
2017-12-28 本文已影响95人
r09er
命令模式概述
生活中,可以通过按钮控制一些电器的开关,例如点灯和风扇,开关在安装之前并不知道开关将会用于点灯还是风扇,所以开关与点灯并无直接的关系.安装好之后开关通过电线与点灯连接,就可以用于控制开灯与关灯,同时相同的开关可以通过切换不同的电线连接来控制不同的电器.这样的生活案例就是命令模式的体现.
将请求的发送者和接收者解耦,我们可以使用一种被称之为命令模式的设计模式来设计系统,在命令模式中,发送者与接收者之间引入了新的命令对象,将发送者的请求封装在命令对象中,再通过命令对象来调用接收者的方法。
责任链模式优缺点
优点
- 降低系统的耦合度。由于请求者与接收者之间不存在直接引用,因此请求者与接收者之间实现完全解耦,相同的请求者可以对应不同的接收者,同样,相同的接收者也可以供不同的请求者使用,两者之间具有良好的独立性。
- 新的命令可以很容易地加入到系统中。由于增加新的具体命令类不会影响到其他类,因此增加新的具体命令类很容易,无须修改原有系统源代码,甚至客户类代码,满足“开闭原则”的要求。
- 可以比较容易地设计一个命令队列或组合命令(宏命令)。
- 为请求的撤销(Undo)和恢复(Redo)操作提供了一种设计和实现方案。
缺点
- 使用命令模式可能会导致系统有过多的具体命令类。因为针对每一个对请求接收者的调用操作都需要设计一个具体命令类,因此在某些系统中可能需要提供大量的具体命令类,这将影响命令模式的使用。
适用场景
- 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。请求调用者无须知道接收者的存在,也无须知道接收者是谁,接收者也无须关心何时被调用。
- 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
- 系统需要将一组操作组合在一起形成宏命令。
示例
有一个平台的公告板系统。该系统提供了一个主菜单(Menu),在主菜单中包含了一些菜单项(MenuItem),可以通过Menu类的addMenuItem()方法增加菜单项。菜单项的主要方法是click(),每一个菜单项包含一个抽象命令类,具体命令类包括OpenCommand(打开命令),CreateCommand(新建命令),EditCommand(编辑命令)等,命令类具有一个execute()方法,用于调用公告板系统界面类(BoardScreen)的open()、create()、edit()等方法。试使用命令模式设计该系统,以便降低MenuItem类与BoardScreen类之间的耦合度。
UML图
UML抽象的执行方法
public abstract class AbstractCommand {
public abstract void execute();
}
具体的命令实现
public class CreateCommand extends AbstractCommand {
@Override
public void execute() {
System.out.println("创建公告板");
}
}
public class OpenCommand extends AbstractCommand {
@Override
public void execute() {
System.out.println("打开公告板");
}
}
public class EditCommand extends AbstractCommand {
@Override
public void execute() {
System.out.println("编辑公告板");
}
}
菜单项(开关)
public class MenuItem {
private String name;//按钮名称
private AbstractCommand abstractCommand;//抽象命令
public MenuItem(String name) {
this.name = name;
}
public void setCommand(AbstractCommand command) {
this.abstractCommand = command;
}
public void click() {
abstractCommand.execute();
}
}
总菜单
public class Menu {
private ArrayList<MenuItem> menuItems ;
public Menu() {
menuItems = new ArrayList<>();
}
public void addMenuItem(MenuItem menuItem){
menuItems.add(menuItem);
}
public void removeMenuItem(MenuItem menuItem){
menuItems.remove(menuItem);
}
public void executeAll(){
for (MenuItem menuItem : menuItems) {
menuItem.click();
}
}
}
调用
public static void main(String[] args) {
MenuItem menuItem1 = new MenuItem("打开");
MenuItem menuItem2 = new MenuItem("新建");
MenuItem menuItem3 = new MenuItem("编辑");
Menu menu = new Menu();
menu.addMenuItem(menuItem1);
menu.addMenuItem(menuItem2);
menu.addMenuItem(menuItem3);
AbstractCommand open,create,edit;
open = new OpenCommand();
create = new CreateCommand();
edit = new EditCommand();
menuItem1.setCommand(create);
menuItem2.setCommand(open);
menuItem3.setCommand(edit);
//单个按钮操作
menuItem1.click();
menuItem2.click();
menuItem3.click();
//执行所有按钮操作
//menu.executeAll();
}
输出结果
创建执行操作
创建公告板
打开执行操作
打开公告板
编辑执行操作
编辑公告板