命令模式的用途:具體的例子多執行緒佇列請求
阿新 • • 發佈:2019-02-04
描述來自於headfirst
命令可以將運算塊打包(一個接受者和一組動作),然後將它傳來傳去,就像是一般的物件一樣。現在,即使在命令物件被建立許久之後,運算依然可以被呼叫。事實上,它甚至可以在不同的執行緒中被呼叫。我們可以利用這樣的特性衍生一些應用,例如:日程安排、執行緒池、工作佇列等。
想象有一個工作佇列:你在某一端新增命令,然後另一端則是執行緒。執行緒進行下面的工作:從佇列中取出一個命令,呼叫它的execute()方法,等待這個呼叫完成,然後將此命令物件丟棄,再取出下一個命令…..
請注意, 工作佇列類和驚醒計算的物件之間完全是解耦的。此刻執行緒可能在進行財務運算,下一個卻在讀取網路資料。工作佇列物件不在乎到底做些什麼,他們只知道取出命令物件,然後呼叫其execute()方法。類似的,它們只要是實現命令模式的物件,就可以放入 佇列裡,當執行緒可用時,就呼叫此物件的execute()方法。
給出了一個大致程式碼,及其測試
這裡簡單處理,預先載入需要處理的工作,然後統一呼叫,目的是使各工作之間互不影響。
(也可以採用多執行緒讀寫,一個讀,一個寫,可以參考這個列子更改)
receiver程式碼
資料庫相關
package headfirst.hd.command.app.receiver;
public class DatabaseOp {
public void add() {
System.out.println("向資料庫新增資料");
}
public void delete() {
System.out .println("向資料庫刪除資料");
}
public void update() {
System.out.println("向資料庫更新資料");
}
}
檔案相關
package headfirst.hd.command.app.receiver;
public class FileOp {
public void upload() {
System.out.println("檔案上傳");
}
public void download() {
System.out.println("檔案下載" );
}
public void md5() {
System.out.println("對檔案進行md5加密");
}
}
網路相關
package headfirst.hd.command.app.receiver;
public class ScoketOp {
public void send() {
System.out.println("向網路中傳送資料");
}
public void receive() {
System.out.println("從網路中接收資料");
}
}
Command 介面程式碼
package headfirst.hd.command.app.interfaces;
public interface Command {
//簡化操作,不帶引數
void execute();
}
concreteCommand程式碼,對應具體功能
package headfirst.hd.command.app.concreteCommand;
import headfirst.hd.command.app.interfaces.Command;
import headfirst.hd.command.app.receiver.DatabaseOp;
public class DbAdd implements Command {
DatabaseOp op;
public DbAdd(DatabaseOp op) {
this.op = op;
}
@Override
public void execute() {
op.add();
}
}
package headfirst.hd.command.app.concreteCommand;
import headfirst.hd.command.app.interfaces.Command;
import headfirst.hd.command.app.receiver.FileOp;
public class FileDownload implements Command {
FileOp op;
public FileDownload(FileOp op) {
super();
this.op = op;
}
@Override
public void execute() {
op.download();
}
}
package headfirst.hd.command.app.concreteCommand;
import headfirst.hd.command.app.interfaces.Command;
import headfirst.hd.command.app.receiver.FileOp;
public class FileUpload implements Command {
FileOp op;
public FileUpload(FileOp op) {
super();
this.op = op;
}
@Override
public void execute() {
op.upload();
}
}
package headfirst.hd.command.app.concreteCommand;
import headfirst.hd.command.app.interfaces.Command;
import headfirst.hd.command.app.receiver.ScoketOp;
public class ScoketReceive implements Command {
ScoketOp op;
public ScoketReceive(ScoketOp op) {
this.op = op;
}
@Override
public void execute() {
op.receive();
}
}
Invoker程式碼,及其輔助類
核心控制器SchedulerControl
package headfirst.hd.command.app.invoker;
import java.util.LinkedList;
import java.util.Queue;
import headfirst.hd.command.app.interfaces.Command;
public class SchedulerControl {
Queue<Command> queue = new LinkedList<Command>();
public void setScheduler(Command command) {
queue.add(command);
}
//開啟多執行緒
public void startComand() throws Exception {
Command command = queue.poll();
while (command != null) {
ThreadUtils.startThread(command);
command = queue.poll();
}
}
}
執行緒輔助類ComandThread
package headfirst.hd.command.app.invoker;
import java.util.Random;
import headfirst.hd.command.app.interfaces.Command;
public class ComandThread implements Runnable {
Command command;
public ComandThread(Command command) {
this.command = command;
}
@Override
public void run() {
System.out.println(command.getClass() + "開始");
//隨機延時 1到10秒,模擬任務需要很久的時間
int nextInt = new Random().nextInt(10);
try {
Thread.sleep(nextInt * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
command.execute();
System.out.println(command.getClass() + "結束, 共用時" + nextInt + "秒");
}
}
執行緒公共方法ThreadUtils ,建立,並開啟執行緒
package headfirst.hd.command.app.invoker;
import headfirst.hd.command.app.interfaces.Command;
public class ThreadUtils {
//開啟多執行緒
public static void startThread(Command command) throws Exception {
ComandThread target = new ComandThread(command);
Thread thread = new Thread(target);
thread.start();
}
}
測試程式碼DriveTest
package headfirst.hd.command.app;
import headfirst.hd.command.app.concreteCommand.DbAdd;
import headfirst.hd.command.app.concreteCommand.FileDownload;
import headfirst.hd.command.app.concreteCommand.FileUpload;
import headfirst.hd.command.app.concreteCommand.ScoketReceive;
import headfirst.hd.command.app.invoker.SchedulerControl;
import headfirst.hd.command.app.receiver.DatabaseOp;
import headfirst.hd.command.app.receiver.FileOp;
import headfirst.hd.command.app.receiver.ScoketOp;
public class DriveTest {
public static void main(String[] args) throws Exception {
//Receiver
DatabaseOp databaseOp = new DatabaseOp();
FileOp fileOp = new FileOp();
ScoketOp scoketOp = new ScoketOp();
//concreteCommand
DbAdd dbAdd = new DbAdd(databaseOp);
FileDownload fileDownload = new FileDownload(fileOp);
FileUpload fileUpload = new FileUpload(fileOp);
ScoketReceive scoketReceive = new ScoketReceive(scoketOp);
//Invoker繫結concreteCommand
SchedulerControl control = new SchedulerControl();
control.setScheduler(dbAdd);
control.setScheduler(fileUpload);
control.setScheduler(fileDownload);
control.setScheduler(scoketReceive);
//再次向資料庫插入資料
control.setScheduler(dbAdd);
//開啟工作佇列
control.startComand();
}
}
class headfirst.hd.command.app.concreteCommand.FileUpload開始
class headfirst.hd.command.app.concreteCommand.DbAdd開始
class headfirst.hd.command.app.concreteCommand.FileDownload開始
class headfirst.hd.command.app.concreteCommand.ScoketReceive開始
class headfirst.hd.command.app.concreteCommand.DbAdd開始
檔案下載
class headfirst.hd.command.app.concreteCommand.FileDownload結束, 共用時1秒
檔案上傳
向資料庫新增資料
class headfirst.hd.command.app.concreteCommand.DbAdd結束, 共用時5秒
class headfirst.hd.command.app.concreteCommand.FileUpload結束, 共用時5秒
從網路中接收資料
class headfirst.hd.command.app.concreteCommand.ScoketReceive結束, 共用時6秒
向資料庫新增資料
class headfirst.hd.command.app.concreteCommand.DbAdd結束, 共用時8秒
測試結果
滿足工作佇列要求,各工作之間互不影響