1. 程式人生 > >命令模式的用途:具體的例子多執行緒佇列請求

命令模式的用途:具體的例子多執行緒佇列請求

描述來自於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

測試結果

滿足工作佇列要求,各工作之間互不影響