隨著每天的學習越來越深入,
接觸到新的模式,也會對於學習過的模式有更深入的認識。
所以之後會更新一下舊的文章,
新增一些圖片或修改一下格式之類的。
命令模式(Command Pattern)有三個主要角色,Invoker
、ICommand
和Receiver
,
是將對行爲進行封裝的典型模式,
將命令的命令接收(請求操作者)
跟執行命令(實際操作者)
之間切分開來。
幾乎所有的類別都可以套用命令模式,但是只有在需要某些特殊功能,
如記錄操作步驟
、取消上次命令
的時候,
比較適合用命令模式。
命令模式有幾個優點:
- 它能較容易的設計一個命令序列。
- 在需要的狀況下,可以較容易的將命令記入日誌。
- 允許接收請求的一方決定是否要否決請求。
- 可以容易的實現對請求的取消和重做。
- 由於加進新的具體命令類別不影響其他類別,因此增加新的具體命令類別很容易。
最後、最大的優點是將請求的物件和執行的物件分開。
-- 大話設計模式 p.355
試著將控制燈光用命令模式實作。
public class Light {
//Receiver可以是任何的類
public void turnOn(){
System.out.println("打開燈");
}
public void turnOff(){
System.out.println("關燈");
}
public void brighter(){
System.out.println("亮度提高");
}
public void darker(){
System.out.println("亮度降低");
}
}
對燈光控制的Command介面
public abstract class Command {
Light light;
public Command(Light light){
this.light = light;
}
public abstract void execute();
}
燈光底下的Command
public class TurnOn extends Command {
public TurnOn(Light light) {
super(light);
}
@Override
public void execute() {
light.turnOn();
}
}
public class TurnOff extends Command {
public TurnOff(Light light) {
super(light);
}
@Override
public void execute() {
light.turnOff();
}
}
public class Brighter extends Command{
public Brighter(Light light) {
super(light);
}
@Override
public void execute() {
light.brighter();
}
}
public class Darker extends Command {
public Darker(Light light) {
super(light);
}
@Override
public void execute() {
light.darker();
}
}
燈光的遙控器,可以儲存commands。
public class Invoker {
private List<Command> commandList = new ArrayList<>();
public void addCommand(Command command) {
commandList.add(command);
}
public void execute(){
for (Command command :
commandList) {
command.execute();
}
}
}
測試一下
public class Test {
@org.junit.jupiter.api.Test
public void test(){
Light light = new Light();
Command turnOn = new TurnOn(light);
Command brighter = new Brighter(light);
Command darker = new Darker(light);
Invoker invoker = new Invoker();
invoker.addCommand(turnOn);
invoker.addCommand(brighter);
invoker.addCommand(brighter);
invoker.addCommand(brighter);
invoker.addCommand(darker);
invoker.execute();
}
}
測試結果
打開燈
亮度提高
亮度提高
亮度提高
亮度降低
實作 - 2
試著實現魔術方塊的Command模式 ⋯
對Tetris Game的操作
public class Tetris {
public Tetris(){
}
public void trunLeft(){
System.out.println("向左轉");
}
public void turnRight(){
System.out.println("向右轉");
}
public void straightDown(){
System.out.println("直接下降");
}
}
魔術方塊的Command介面
public abstract class ICommandTetris {
// 抽象的命令
protected Tetris tetris;
public ICommandTetris(Tetris tetris) {
this.tetris = tetris;
}
public abstract void execute();
}
三種對魔術方塊的操作
public class TurnLeft extends ICommandTetris {
public TurnLeft(Tetris tetris) {
super(tetris);
}
@Override
public void execute() {
tetris.trunLeft();
}
}
public class TurnRight extends ICommandTetris{
public TurnRight(Tetris tetris) {
super(tetris);
}
@Override
public void execute() {
tetris.turnRight();
}
}
public class StraightDown extends ICommandTetris
{
public StraightDown(Tetris tetris) {
super(tetris);
}
@Override
public void execute() {
tetris.straightDown();
}
}
遊戲的操縱者
public class Invoker {
ICommandTetris command;
public Invoker(ICommandTetris command){
this.command = command;
}
public void setCommand(ICommandTetris command){
this.command = command;
}
public void invoke(){
command.execute();
}
}
測試一下
public class Test {
@org.junit.jupiter.api.Test
public void test(){
Tetris tetris = new Tetris();
ICommandTetris commandLeft = new TurnLeft(tetris);
ICommandTetris commandRight = new TurnRight(tetris);
ICommandTetris commandDown= new StraightDown(tetris);
Invoker invoker = new Invoker(commandLeft);
invoker.invoke();
invoker.setCommand(commandRight);
invoker.invoke();
invoker.setCommand(commandDown);
invoker.invoke();
}
}
測試結果
向左轉
向右轉
直接下降
命令模式實現起來沒有很困難,幾乎所有的類別都可以套用命令模式,但是無謂的套用只會增加類別的數量。所以在有適合使用命令模式的需求,到那時再重構就好。