1. 程式人生 > >設計模式-command模式

設計模式-command模式

定義命令模式

  命令模式將“請求”封裝成物件,以便使用不同的請求、佇列或者日誌來引數化其他物件。命令模式也支援可撤銷的操作。命令物件將動作和接收者包進物件中。

應用場景

  在面向物件的軟體設計中,經常會遇到一個(或一系列)物件,物件本身的資料儲存與物件的操作耦合在一起。例如一個物件有add(),edit(),delete()方法,這樣物件支援的方法很難擴充套件,如果需要加入update()就必須修改程式碼,客戶端與物件也是緊耦合的。命令模式是將一類物件的功能(行為,功能)抽象成一個命令物件,客戶端在使用的時候,只與該命令物件打交道,而不用與物件打交道,分離命令的請求者和命令的執行者,降低了耦合性,可以使用不同的請求對客戶進行引數化提高了程式設計的靈活性

命令模式的類圖

    下面是Head First設計模式上面定義命令模式的類圖 遙控器問題:有一個附著多組開關按鈕的遙控器,帶有可程式設計插槽,每個都可以指定到一個不同的家電裝置;有很多廠商開發的各種家電裝置控制類;希望建立一組API,讓每個插槽控制一個或一組裝置。下面是Head First設計模式上實現遙控器問題的類圖

 遙控器問題:

可以把遙控器的按鈕看做是一個命令,按下命令的時候不需要知道命令是怎麼執行的,我們可以將遙控器每個按鍵看做是一個命令物件,實現的時候用陣列來表示遙控器的按鈕位置,然後為陣列賦值具體對應的命令物件

class Light {
	String location = "";

	public Light(String location) {
		this.location = location;
	}

	public void on() {
		System.out.println(location + " light is on");
	}

	public void off() {
		System.out.println(location + " light is off");
	}
}
//命令類實現
class LivingroomLightOffCommand implements Command {
	Light light;

	public LivingroomLightOffCommand(Light light) {
		this.light = light;
	}

	public void execute() {
		light.off();
	}
}
 class LivingroomLightOnCommand implements Command {
	Light light;

	public LivingroomLightOnCommand(Light light) {
		this.light = light;
	}

	public void execute() {
		light.on();
	}
}
class Stereo {
    String location;

    public Stereo(String location) {
        this.location = location;
    }

    public void on() {
        System.out.println(location + " stereo is on");
    }

    public void off() {
        System.out.println(location + " stereo is off");
    }

    public void setCD() {
        System.out.println(location + " stereo is set for CD input");
    }

    public void setDVD() {
        System.out.println(location + " stereo is set for DVD input");
    }

    public void setRadio() {
        System.out.println(location + " stereo is set for Radio");
    }

    public void setVolume(int volume) {
        // code to set the volume
        // valid range: 1-11 (after all 11 is better than 10, right?)
        System.out.println(location + " Stereo volume set to " + volume);
    }
}
 class StereoOffCommand implements Command {
    Stereo stereo;
 
    public StereoOffCommand(Stereo stereo) {
        this.stereo = stereo;
    }
 
    public void execute() {
        stereo.off();
    }
}
 class StereoOnWithCDCommand implements Command {
    Stereo stereo;
 
    public StereoOnWithCDCommand(Stereo stereo) {
        this.stereo = stereo;
    }
 
    public void execute() {
        stereo.on();
        stereo.setCD();
        stereo.setVolume(11);
    }
}

 class NoCommand implements Command {
    public void execute() { }
    public void undo() { }
}
 // This is the invoker
//
//invoker相當於訂單。它可以呼叫execute方法
 class RemoteControl {
	Command[] onCommands;
	Command[] offCommands;
 
	public RemoteControl() {     //在構造器例項化並初始化兩個開與關的陣列
		onCommands = new Command[7];
		offCommands = new Command[7];
 
		Command noCommand = new NoCommand();
		for (int i = 0; i < 7; i++) {
			onCommands[i] = noCommand;
			offCommands[i] = noCommand; //在構造器中將每個插槽都預先指定成noCommand物件,以便確定每個插槽永遠都有命令物件
		}
	}
  //將命令記錄在開關陣列中對應的插槽位置插槽
	public void setCommand(int slot, Command onCommand, Command offCommand) {
		onCommands[slot] = onCommand;
		offCommands[slot] = offCommand;
	}
  //按下按鍵 呼叫execute
	public void onButtonWasPushed(int slot) {
		onCommands[slot].execute();
	}

	public void offButtonWasPushed(int slot) {
		offCommands[slot].execute();
	}
  
	public String toString() {
		StringBuffer stringBuff = new StringBuffer();
		stringBuff.append("\n------ Remote Control -------\n");
		for (int i = 0; i < onCommands.length; i++) {
			stringBuff.append("[slot " + i + "] " + onCommands[i].getClass().getName()
				+ "    " + offCommands[i].getClass().getName() + "\n");
		}
		return stringBuff.toString();
	}
}
//測試
public class RemoteLoader {
 
	public static void main(String[] args) {
		RemoteControl remoteControl = new RemoteControl();
 
		Light livingRoomLight = new Light("Living Room");
		Light kitchenLight = new Light("Kitchen");
		CeilingFan ceilingFan= new CeilingFan("Living Room");
		GarageDoor garageDoor = new GarageDoor("");
		Stereo stereo = new Stereo("Living Room");
  
		LightOnCommand livingRoomLightOn = 
				new LightOnCommand(livingRoomLight);
		LightOffCommand livingRoomLightOff = 
				new LightOffCommand(livingRoomLight);
		LightOnCommand kitchenLightOn = 
				new LightOnCommand(kitchenLight);
		LightOffCommand kitchenLightOff = 
				new LightOffCommand(kitchenLight);

		StereoOnWithCDCommand stereoOnWithCD =
				new StereoOnWithCDCommand(stereo);
		StereoOffCommand  stereoOff =
				new StereoOffCommand(stereo);
 
		remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff);
		remoteControl.setCommand(1, stereoOnWithCD, stereoOff);
  
		System.out.println(remoteControl)
 
		remoteControl.onButtonWasPushed(0);
		remoteControl.offButtonWasPushed(0);
		remoteControl.onButtonWasPushed(1);
		remoteControl.offButtonWasPushed(1);

	}
}
撤銷操作的實現

 新加入undo方法 然後每個具體的命令類都實現這個方法:undo方法中呼叫的操作和execute()方法中的操作相反,比如on的反面是off。

 遙控器類也要做一些修改:加入新的例項變數記錄上一個操作,當按下撤銷按鈕,就呼叫該例項變數的undo()方法。

 如果撤銷到某一個狀態需要記錄一些變數值,則在execute()方法中加入儲存操作前狀態數值的語句,然後在undo()的時候恢復。

例如將一個控制電風扇的命令加上undo方法

public class CeilingFanOffCommand implements Command {
	CeilingFan ceilingFan;
	int prevSpeed;
  
	public CeilingFanOffCommand(CeilingFan ceilingFan) {
		this.ceilingFan = ceilingFan;
	}
 
	public void execute() {
		prevSpeed = ceilingFan.getSpeed();
		ceilingFan.off();
	}
 
	public void undo() {
		if (prevSpeed == CeilingFan.HIGH) {
			ceilingFan.high();
		} else if (prevSpeed == CeilingFan.MEDIUM) {
			ceilingFan.medium();
		} else if (prevSpeed == CeilingFan.LOW) {
			ceilingFan.low();
		} else if (prevSpeed == CeilingFan.OFF) {
			ceilingFan.off();
		}
	}
}

實現Party模式

   實現Party模式就是按下一個遙控器開關按鈕會有一系列的執行者j接收到命令按一定的次序執行操作。實現得方法是使用巨集命令,用命令陣列儲存一大堆命令,在execute()方法中用一個for迴圈遍歷這個陣列,依次執行陣列各個執行物件的execute

//實現命令陣列
class MacroCommand implements Command {
	Command[] commands;
 
	public MacroCommand(Command[] commands) {
		this.commands = commands;
	}
 
	public void execute() {
		for (int i = 0; i < commands.length; i++) {
			commands[i].execute();
		}
	}
 
	public void undo() {
		for (int i = 0; i < commands.length; i++) {
			commands[i].undo();
		}
	}
}
//使用巨集命令示例
    Command[] partyOn = { lightOn, stereoOn, tvOn, hottubOn};
		Command[] partyOff = { lightOff, stereoOff, tvOff, hottubOff};
  
		MacroCommand partyOnMacro = new MacroCommand(partyOn);
		MacroCommand partyOffMacro = new MacroCommand(partyOff);
 
		remoteControl.setCommand(0, partyOnMacro, partyOffMacro);
  
		System.out.println(remoteControl);
		System.out.println("--- Pushing Macro On---");
		remoteControl.onButtonWasPushed(0);
		System.out.println("--- Pushing Macro Off---");
		remoteControl.offButtonWasPushed(0);



相關推薦

設計模式command模式

定義命令模式   命令模式將“請求”封裝成物件,以便使用不同的請求、佇列或者日誌來引數化其他物件。命令模式也支援可撤銷的操作。命令物件將動作和接收者包進物件中。 應用場景   在面向物件的軟體設計中,經常會遇到一個(或一系列)物件,物件本身的資料儲存與物件的操作耦合在一

設計模式命令模式(command pattern)

名稱:命令模式 說說:這其實和小時候我們傳紙條是一樣一樣的,一張紙條代表一條命令 動機: 適用性: 參與者: 結果:將一個請求封裝為一個物件 類圖: 說明:一個命令(請求)就是一個例項(命令物件 = 動作的執行者 + 要執行的行為),傳送一個命令就是傳遞一個命令引數。 d

設計模式行為模式

a)結構:注:1)使多個物件都有機會處理請求,從而避免請求的傳送者和接收者之間耦合關係。將這些物件連成一條鏈,並沿著這條鏈傳遞該請求,直到有一個物件處理她為止。b)優點:i.降低耦合程度。每個物件僅需知道如何將請求往後轉發。(每個物件只需保留一個後繼的引用)ii.在職責分發方

設計模式工廠模式(FactoryMethod)

我的github 對於一個Java應用來說,會存在很多的呼叫關係,比如物件A的方法呼叫物件B的方法,就說物件A依賴物件B. 常規的做法是在類A中例項化B物件,再進行使用.但是這裡存在一個問題,如果將來進行應用升級改進,不再使用B的方法而是使用物件C的方法.如

【python + 設計模式command模式

command模式個人覺得主要的作用就是,將需要執行的action分離並封裝,完成對該類行為的一些類似於command的操作。 比如:執行記錄、統計、撤消、佇列等。 這種模式在python中沒有涉及到啥特殊操作。 """ *TL;DR80 Encapsulates all

設計模式之命令模式(Command)摘錄

single 而是 names 都得 結構 意圖 iterator nbsp 軟件 23種GOF設計模式一般分為三大類:創建型模式、結構型模式、行為模式。創建型模式抽象了實例化過程,它們幫助一個系統獨立於怎樣創建、組合和表示它的那些對象。一個類創建型模式使用繼承改變被實例

設計模式之命令模式 Command

sta clas ide class open cli private 2017年 命令模式 介紹 角色 使用場景 代碼實現 public interface Command { //這個方法是一個返回結果為空的方法 //實際項目中,可

c#設計模式系列:命令模式Command Pattern)

為我 pattern 代碼 spa pro round 產生 技術分享 image 引言 命令模式,我感覺“命令”就是任務,執行了命令就完成了一個任務。或者說,命令是任務,我們再從這個名字上並不知道命令的發出者和接受者分別是誰,為什麽呢?因為我們並不關心他們是誰,發出命令

C#設計模式(15)——命令模式Command Pattern)

兩個 學院 做的 text server trac handle 接受 color 一、前言   之前一直在忙於工作上的事情,關於設計模式系列一直沒更新,最近項目中發現,對於設計模式的了解是必不可少的,當然對於設計模式的應用那更是重要,可以說是否懂得應用設計模式在項目中是衡

【Python設計模式】06 觀察者模式瞭解物件的情況

六、觀察者模式-瞭解物件的情況 這章可以討論行為型設計模式:觀察者設計模式 本章主題 行為型設計模式簡介 觀察者設計模式及其 UML圖 利用 Python3.x程式碼實現一個真實用例 鬆耦合的強大威力 常見問答 1. 行為型模式簡介

【Python設計模式】04 門面模式與門面相適

四、門面模式-與門面相適 Python3.x 本章研究結構型設計模式:門面模式 本章主題 結構型設計模式概要 利用UML圖理解門面設計模式 Python3.x實現程式碼的真實用例 門面模式與最少知識原則 1. 理解結構型設計模式

Command模式(命令設計模式

Command?? 把方法的呼叫用一個類的例項來承載,要管理工作的歷史記錄,建立這些方法執行的命令的集合,只需管理這些例項的集合即可,而且還可以隨時再次執行過去的命令,或是將多個過去的命令整合為一個新命令並執行。稱之為Command設計模式 那裡合適使用: Command有時也被稱為事件(event

重走Java設計模式——命令模式Command Pattern)

命令模式 定義 命令模式(Command Pattern)是一種資料驅動的設計模式,它屬於行為型模式。請求以命令的形式包裹在物件中,並傳給呼叫物件。呼叫物件尋找可以處理該命令的合適的物件,並把該命令傳給相應的物件,該物件執行命令。 命令模式設計角色

設計模式之命令模式Command Pattern)

摘要 命令模式(Command Pattern)是一種資料驅動的設計模式,它屬於行為型模式。請求以命令的形式包裹在物件中,並傳給呼叫物件。呼叫 介紹 意圖:將一個請求封裝成一個物件,從而使您可以用不同的請求對客戶進行引數化。 主要解決:在軟體系統中,行為請求者與行為實現者通常是一種緊

二十三種設計模式[14] - 命令模式(Command Pattern)

前言        命令模式,物件行為型模式的一種。它幫助我們將功能的呼叫者與實現者之間解耦(甚至完全解耦)。呼叫者與實現者之間並不是直接引用關係,呼叫者只需要知道如何傳送當前功能的請求即可,而不用關心該請求由誰在何時完成。   

設計模式(Java)—Command模式

一個類在進行工作時會呼叫自己或是其他類的方法,雖然呼叫結果會反映在物件的狀態中,但是並不會留下工作的歷史紀錄。 這時,如果有一個類,用來表示進行這項工作的命令就會方便很多。每一項想做的工作就不再是方法的呼叫這種動態處理了,而是一個表示命令的類的例項,既可以用物來

設計模式-命令模式Command

命令模式:將一個請求封裝為一個物件,從而可用不同的請求對客戶進行引數化;對請求排隊或記錄日誌,以及支援可撤銷的操作,將”發出請求的物件”和”接收與執行這些請求的物件”分隔開來。   角色和職責: 1.Command:    宣告執行操作的介面 2.Concrete Co

設計模式之命令模式(Command Pattern)

命令模式定義 命令模式是一個高內聚的模式。Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requ

Java23種設計模式【15】----》命令模式command

專案中用到的不多 一、介紹 通過抽象一個新的類,對發的請求和命令快取處理後(記錄日誌,記錄操作前狀態),再轉發給命令的執行者; 例如:資料庫事物的底層就是命令模式 二、結構 三、開發中的場景 四、類圖   五、程式碼實現  1、真正的命令執行者(

Java設計模式之從[打飛機遊戲中的控制器]分析命令(Command)模式

  首先請允許我囉嗦幾句。為什麼我們在軟體設計過程中強調設計模式?為軟體增加設計模式確實會增加一定的程式碼複雜程度,但是它的好處是無窮的。它可以使得軟體更加易於擴充套件而無需改變原始碼。“解耦”是設計模式中的一個關鍵詞。例如,對於某個物件obj,在呼叫obj.method(