北风设计模式课程---29、命令模式
一、总结
一句话总结:
整体系统如何初始做好设计,会非常节约时间,而无需管事大型项目还是小型项目,无需管事面向过程还是面向对象
命令模式就是封装了类的调用:一个类的命令列表里面存各种类,然后遍历调用这些类的方法
1、如果中小型项目的结构通过MVC本身就比较清晰了,还有必要过度使用设计模式么?
没必要:设计模式虽然让代码更加工整了,但是也增加了很多类和很多代码,不一定划得来
面向过程转面向对象也很容易。重构一下代码就好。然后可以按照需求增加这些设计模式。
整体系统如何初始做好设计,会非常节约时间,而无需管事大型项目还是小型项目,无需管事面向过程还是面向对象
2、面向对象编程和面向过程编程?
照我看来,黑猫白猫,能抓到老鼠的就是好猫。面向过程配上mvc在中小型项目中也是够用的。
面向过程转面向对象也很容易。重构一下代码就好。然后可以按照需求增加这些设计模式。
整体系统如何初始做好设计,会非常节约时间,而无需管事大型项目还是小型项目,无需管事面向过程还是面向对象
初始建议面向对象编程,结构清晰,不易出错,反而会节约时间的
3、什么是命令模式?
Command模式通过被称为Command的类封装了对目标对象的调用行为以及调用参数。
Command模式也叫命令模式 ,是行为设计模
式的一种。Command模式通过被称为
Command的类封装了对目标对象的调用行为以
及调用参数。
4、在面向对象的程序设计中,一个对象调用另一个对象,一般情况下的调用过程是怎样的?
1、创建目标对象实例;设置调用参数;调用目标对象的方法。
2、命令模式:但在有些情况下有必要使用一个专门的类对这种调用过程加以封装,我们把这种专门的类称作command类。
5、命令模式的应用场景?
- 整个调用过程比较繁杂,或者存在多处这种调用。这时,使用Command类对该调用加以封装,便于功能的再利用。
- 调用前后需要对调用参数进行某些处理。
- 调用前后需要进行某些额外处理,比如日志,缓存,记录历史操作等。
6、命令模式 实例?
有卖苹果命令类,有卖香蕉命令类。小商贩Peddler类封装了卖苹果和卖香蕉命令。有服务员Waiter类,里面有命令列表数据结构,有添加命令和删除命令方法,也有sail方法就是一次调用苹果或香蕉命令类的sail方法。
7、命令模式的角色和职责?
1、Command:Command抽象类。Command.java
2、ConcreteCommand:Command的具体实现类。AppleCommand.java;BananaCommand.java
3、Receiver:需要被调用的目标对象。Peddler.java
4、Invorker:通过Invorker执行Command对象。Waiter.java
二、内容在总结中
1、相关知识
ConcreteCommand:Command的具体实现类。AppleCommand.java;BananaCommand.java
Receiver:需要被调用的目标对象。Peddler.java
Invorker:通过Invorker执行Command对象。Waiter.java
2、代码
Command:Command抽象类。Command.java
package com.ibeifemg.ex4; public abstract class Command { private Peddler peddler; public Command(Peddler peddler) { this.peddler = peddler; } public Peddler getPeddler() { return peddler; } public void setPeddler(Peddler peddler) { this.peddler = peddler; } public abstract void sail(); }
ConcreteCommand:Command的具体实现类。
AppleCommand.java;
package com.ibeifemg.ex4; public class AppleCommand extends Command { public AppleCommand(Peddler peddler) { super(peddler); } public void sail() { this.getPeddler().sailApple(); } }
BananaCommand.java
package com.ibeifemg.ex4; public class BananaCommand extends Command{ public BananaCommand(Peddler peddler) { super(peddler); } public void sail() { this.getPeddler().sailBanana(); } }
Receiver:需要被调用的目标对象。Peddler.java
package com.ibeifemg.ex4; /* * 小商贩 */ public class Peddler { //卖苹果 public void sailApple() { System.out.println("卖苹果"); } //卖香蕉 public void sailBanana() { System.out.println("卖香蕉"); } }
Invorker:通过Invorker执行Command对象。Waiter.java
package com.ibeifemg.ex4; import java.util.ArrayList; import java.util.List; public class Waiter { private List<Command> commands = new ArrayList<Command>(); public void setOrder(Command command) { commands.add(command); } public void removeOrder(Command command) { commands.remove(command); } public void sail() { for(Command command : commands) { command.sail(); } } }
客户端调用:
package com.ibeifemg.ex4; public class MainClass { public static void main(String[] args) { Peddler peddler = new Peddler(); // peddler.sailApple(); // peddler.sailBanana(); Command appleCommand = new AppleCommand(peddler); Command bananaCommand = new BananaCommand(peddler); // appleCommand.sail(); // bananaCommand.sail(); Waiter waiter = new Waiter(); //下订单 waiter.setOrder(appleCommand); waiter.setOrder(bananaCommand); //移除订单某项 waiter.removeOrder(appleCommand); waiter.sail(); } }
三、java设计模式-----23、命令模式
转自或参考:java设计模式-----23、命令模式
https://www.cnblogs.com/xiaobai1226/p/8651632.html
概念:
Command模式也叫命令模式 ,是行为设计模式的一种。Command模式通过被称为Command的类封装了对目标对象的调用行为以及调用参数。
命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
主要解决:
在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,实现二
者之间的松耦合。这就是命令模式(Command Pattern)。
下面,举一个小例子,但不是使用命令模式实现的
新建一个Peddler类,是一个卖水果的小商贩
1 /* 2 * 小商贩 3 */ 4 public class Peddler { 5 /* 6 * 卖苹果 7 */ 8 public void sailApple(){ 9 System.out.println("卖苹果"); 10 } 11 12 /* 13 * 卖香蕉 14 */ 15 public void sailBanana(){ 16 System.out.println("卖香蕉"); 17 } 18 }
再建一个客户端
1 public class MainClass { 2 public static void main(String[] args) { 3 Peddler peddler = new Peddler(); 4 peddler.sailApple(); 5 peddler.sailBanana(); 6 } 7 }
结果:
命令模式的应用场景
在面向对象的程序设计中,一个对象调用另一个对象,一般情况下的调用过程是:创建目标对象实例;设置调用参数;调用目标对象的方法(像刚才的例子MainClass中,创建Peddler实例,再调度其中的方法)。
但在有些情况下有必要使用一个专门的类对这种调用过程加以封装,我们把这种专门的类称作command类。
1、整个调用过程比较繁杂,或者存在多处这种调用。这时,使用Command类对该调用加以封装,便于功能的再利用。
2、调用前后需要对调用参数进行某些处理。
3、调用前后需要进行某些额外处理,比如日志,缓存,记录历史操作等。
命令模式的结构
命令模式的角色和职责
1、Command:Command抽象类,定义命令的接口,声明执行的方法。。
2、ConcreteCommand:Command的具体实现类,命令接口实现对象,是“虚”的实现;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
3、Receiver:需要被调用的目标对象,接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
4、Invorker:通过Invorker执行Command对象,要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
5、Client:创建具体的命令对象,并且设置命令对象的接收者。注意这个不是我们常规意义上的客户端,而是在组装命令对象和接收者,或许,把这个Client称为装配者会更好理解,因为真正使用命令的客户端是从Invoker来触发执行。
当然,我们的例子非常简单,用不到命令模式,我们假设操作很复杂,用命令模式改造一下
首先,创建类对调用过程进行一个封装,先创建一个Command抽象父类
1 public abstract class Command { 2 //包含一个Receiver的引用 3 private Peddler peddler; 4 5 public Command(Peddler peddler) { 6 super(); 7 this.peddler = peddler; 8 } 9 10 public Peddler getPeddler() { 11 return peddler; 12 } 13 14 public void setPeddler(Peddler peddler) { 15 this.peddler = peddler; 16 } 17 18 public abstract void sail(); 19 }
接下来创建ConcreteCommand,每一个操作都要创建一个,所以我们要创建两个Apple与Banana
1 /* 2 * Apple 3 */ 4 public class AppleCommand extends Command{ 5 6 public AppleCommand(Peddler peddler) { 7 super(peddler); 8 } 9 10 @Override 11 public void sail() { 12 //还可以在这句话前后做额外的处理 13 this.getPeddler().sailApple(); 14 } 15 16 }
1 /* 2 * Banana 3 */ 4 public class BananaCommand extends Command{ 5 6 public BananaCommand(Peddler peddler) { 7 super(peddler); 8 } 9 10 @Override 11 public void sail() { 12 //还可以在这句话前后做额外的处理 13 this.getPeddler().sailBanana(); 14 } 15 16 }
最后,修改MainClass
1 public class MainClass { 2 public static void main(String[] args) { 3 Peddler peddler = new Peddler(); 4 Command appleCommand = new AppleCommand(peddler); 5 Command bananaCommand = new BananaCommand(peddler); 6 7 appleCommand.sail(); 8 bananaCommand.sail(); 9 10 } 11 }
但是这样还不够好,可以看到这是直接由命令来调用sail方法的,这样不好,我们希望由专人来卖东西,就像人家请了一个服务员一样,所以我们再新建一个Invorker
public class Waiter { private Command command; public Command getCommand() { return command; } public void setCommand(Command command) { this.command = command; } public void sail(){ command.sail(); } }
再修改客户端
1 public class MainClass { 2 public static void main(String[] args) { 3 Peddler peddler = new Peddler(); 4 Command appleCommand = new AppleCommand(peddler); 5 Command bananaCommand = new BananaCommand(peddler); 6 7 Waiter waiter = new Waiter(); 8 waiter.setCommand(appleCommand); 9 waiter.sail(); 10 11 waiter.setCommand(bananaCommand); 12 waiter.sail(); 13 14 } 15 }
这样Client就直接与Invorker进行通话
我们现在只能添加命令,却不能移除命令,,而且一次只能有一个命令,我们继续改造
1 public class Waiter { 2 private Map<String,Command> commands; 3 4 public Map<String, Command> getCommands() { 5 if(commands == null){ 6 commands = new HashMap<String,Command>(); 7 } 8 9 return commands; 10 } 11 12 public void setCommand(String key, Command command) { 13 if(commands == null){ 14 commands = new HashMap<String,Command>(); 15 } 16 commands.put(key, command); 17 } 18 19 public void RemoveCommand(String key) { 20 commands.remove(key); 21 } 22 23 public void sail(String key){ 24 commands.get(key).sail(); 25 } 26 }
Client
1 public class MainClass { 2 public static void main(String[] args) { 3 Peddler peddler = new Peddler(); 4 Command appleCommand = new AppleCommand(peddler); 5 Command bananaCommand = new BananaCommand(peddler); 6 7 Waiter waiter = new Waiter(); 8 waiter.setCommand("apple", appleCommand); 9 waiter.setCommand("banana", bananaCommand); 10 11 waiter.sail("apple"); 12 waiter.sail("banana"); 13 14 waiter.RemoveCommand("apple"); 15 16 } 17 }
这样,就完成了,一个命令模式的例子
命令模式的优缺点
优点: 1、降低了系统耦合度。
2、新的命令可以很容易添加到系统中去。
缺点:使用命令模式可能会导致某些系统有过多的具体命令类。