1. 程式人生 > >設計模式(9):命令模式

設計模式(9):命令模式

命令模式:

定義:

將一個請求封裝成一個物件,從而讓你使用不同的請求把客戶端引數化,對請求排隊或者記錄請求日誌,可以提供命令的撤銷和恢復功能。

通用類圖:

Receiver接受者角色:

該角色就是幹活的角色,命令傳遞到這裡是應該被執行的

Command命令角色

需要執行的所有命令都在這裡宣告

Invoker呼叫者角色

接收到命令並執行命令。

優缺點:

優點:

類間解耦

呼叫者角色與接受者角色之間沒有任何依賴關係,呼叫者實現功能時只需要呼叫Command抽象類的execute方法就可以,不需要了解到底是哪個接受者執行

可擴充套件性

Command的子類可以非常容易的擴充套件,而呼叫者Invoker和高層次的Client不產生嚴重的程式碼耦合

命令模式結合其他模式會更優秀

命令模式可以結合責任鏈模式,實現命令族解析任務;結合模板方法模式,則可以減少Command子類的膨脹問題。

缺點:

如果有N個命令,Command的子類就是N個,容易膨脹。

舉個例子:

實現一個專案,該專案的成員分工採用了常規的分工方式:需求組、美工組、程式碼組

abstract class Group {
	public abstract void find();

	public abstract void add();

	public abstract void delete();

	public abstract void change();

	public abstract void plan();

}

// 需求組
class RequirementGroup extends Group {

	public void find() {
		System.out.println("找到需求組---");
	}

	// 增加一項需求
	public void add() {
		System.out.println("客戶要求增加一項需求---");
	}

	// 客戶要求刪除一項需求
	public void delete() {
		System.out.println("客戶要求刪除一項需求---");
	}

	public void change() {
		System.out.println("客戶要求修改一項需求---");
	}

	public void plan() {
		System.out.println("客戶要求變更計劃---");
	}

}

// 美工組

class PageGroup extends Group {

	public void find() {
		System.out.println("找到美工組---");
	}

	public void add() {
		System.out.println("客戶要求增加一個頁面---");
	}

	public void delete() {
		System.out.println("客戶要求刪除一個頁面---");
	}

	public void change() {
		System.out.println("客戶要求修改一個頁面---");
	}

	public void plan() {
		System.out.println("客戶要求頁面變更計劃---");
	}

}

class CodeGroup extends Group {

	public void find() {
		System.out.println("找到程式碼組---");
	}

	public void add() {
		System.out.println("客戶要求增加一項功能---");
	}

	public void delete() {
		System.out.println("客戶要求刪除一項功能---");
	}

	public void change() {
		System.out.println("客戶要求修改一項功能---");
	}

	public void plan() {
		System.out.println("客戶要求程式碼變更計劃---");
	}

}

public class Client {

	public static void main(String[] args) {
		 System.out.println("----------客戶要求增加一項需求----------");
		 Group rg = new RequirementGroup();
		 rg.find();
		 rg.add();
		 rg.plan();
	}
}

在原有類圖上增加了一個Invoker類,其作用是根據客戶的命令安排不同的組員進行工作。但是在系統設計中,字串沒有約束力,根據字串判斷相關的業務邏輯不是一個優秀的解決方案。

解決方案是對客戶發出的命令進行封裝,每個命令是一個物件,避免客戶、負責人、組員之間的交流誤差,封裝後的結果就是客戶只要說一個命令,我的專案組就立刻開始啟動,不用思考、解析命令字串。

Command抽象類只有一個方法execute,其作用就是執行命令,子類非常堅決的解決該命令。

Command抽象類:客戶發給我們的命令,定義三個工作組的成員變數,供子類使用;定義一個抽象方法execute,由子類實現。

Invoker實現類:專案接頭負責人,setCommand接收客戶發給我們的命令,action方法是執行客戶的命令

抽象命令類:

abstract class Command {
	protected RequirementGroup rg = new RequirementGroup();
	protected PageGroup pg = new PageGroup();
	protected CodeGroup cg = new CodeGroup();

	public abstract void execute();
}

需要什麼功能就 繼承該類,並實現execute方法

增加需求:

// 增加需求的命令
class AddRequirementCommand extends Command {
	// 執行增加一項需求的命令
	public void execute() {
		super.rg.find();
		super.rg.add();
		super.rg.plan();
	}

}

刪除一個頁面:

class DeletePageCommand extends Command {
	// 執行刪除一個頁面的命令
	public void execute() {
		super.pg.find();
		super.pg.delete();
		super.pg.plan();
	}
}

Invoker類:

class Invoker {
	private Command command;

	public void setCommand(Command _command) {
		this.command = _command;
	}

	// 執行客戶的命令
	public void action() {
		this.command.execute();
	}
}

增加一個需求Client:

public class Client {

	public static void main(String[] args) {
		Invoker invoker = new Invoker();
		System.out.println("-------客戶要求增加一項需求---------");
		Command command = new AddRequirementCommand();
		invoker.setCommand(command);
		invoker.action();
	}
}

刪除一個頁面Client:

public class Client {

	public static void main(String[] args) {
		Invoker invoker = new Invoker();
		System.out.println("-------客戶要求增加一項需求---------");
//		Command command = new AddRequirementCommand();
		Command command = new DeletePageCommand();
		invoker.setCommand(command);
		invoker.action();
	}
}

只需要修改很少就可以實現功能的轉變。