java基礎_設計模式_命令模式二(以計算機讀取內存和硬盤爲例)

我是野豬。

題目的要求如下:

“計算機系統中存在多個具有I/O操作的組件,比如內存、硬盤、聲卡等;這些I/O組件都具有讀和寫的操作。

假設計算機系統要對這些I/O組件的操作統一管理,並把它們的操作(由用戶代碼觸發)存放到系統中的唯一的一個隊列中。

假設當前系統有兩個線程,可以通過一個統一的接口處理隊列中命令,但只能互斥的訪問該隊列

此外,線程處理一個命令之後,爲了便於觀看,都隨機的等待1-4s。

請選擇合適的模式來模擬這個過程。PS:不考慮I/O組件自身讀寫的互斥問題,輸出一跳語句來表示讀、寫操作即可。”


分析過程:

1.創建具體的組件,比如RAM和DIESK(內存和硬盤);

2.創建具體的指令;

3.創建存放指令的隊列(爲保證只能互斥訪問該隊列設計成單列模式);

4.運行時,指令放入隊列中,創建線程,啓動線程,查看運行結果。


1.創建組件(抽象父類和其有具體實現的子類):

/**
 * 代指計算機中任何一個器件
 * 功能輸入和輸出
 * 真正能執行組件讀、寫操作的是組件本身;
 */

public abstract class Compent {

    protected final String name;

    public Compent(String name) {
        this.name = name;
    }

    public abstract void read();

    public abstract void write();

}

/**
 * 具體的控件
 * Ram 內存
 */

public class RAM extends Compent {

    public RAM(String name) {
        super(name);
    }

    @Override
    public void read() {
        System.out.println(name + " is reading");
    }

    @Override
    public void write() {
        System.out.println(name + " is writtng");
    }
}
/**
 * 具體控件 DIESK
 */

public class DIESK extends Compent {
    private DIESK(String name) {
        super(name);
    }

    @Override
    public void read() {
        System.out.println(name + " is reading");
    }

    @Override
    public void write() {
        System.out.println(name + " is writting");
    }
}
2.創建命令(命令的父類和具體到每一個I/O組件上的讀寫命令):
通過一個統一的接口處理隊列中命令;代碼如下,很簡單:

/**
 * 接口 職責就是執行命令
 */

public interface Command {
    void execute();
}
/**
 * 具體的硬盤讀命令
 */

public class DieskReadCommand implements Command {
    
    Compent diesk;

    public DieskReadCommand(Compent compent) {
        this.diesk = compent;
    }

    @Override
    public void execute() {
        //執行什麼?執行的是內存的讀操作
        diesk.read();
    }
}
/**
 * 具體的硬盤寫命令
 */

public class DieskWriteCommand implements Command {
    
    Compent diesk;

    public DieskWriteCommand(Compent compent) {
        this.diesk = compent;
    }
    @Override
    public void execute() {
        //執行什麼?執行的是內存的讀操作
        diesk.write();
    }
}
/**
 * 具體的內存讀命令
 */

public class RamReadCommand implements Command {

    Compent ram;
    public RamReadCommand (Compent compent) {
        this.ram = compent;
    }

    @Override
    public void execute() {
        //執行什麼?執行的是內存的讀操作
        ram.read();
    }
}
/**
 * 具體的內存的寫命令
 */

public class RamWriteCommand implements Command {
    
    Compent ram;
    public RamWriteCommand(Compent compent) {
        this.ram = compent;
    }

    @Override
    public void execute() {
        //執行什麼?執行的是內存的讀操作
        ram.write();
    }
}

3.使用單例模式創建存放指令的隊列(隊列應該具有插入和獲取指令的方法):

import java.util.LinkedList;
import java.util.Queue;

/**
 * 存放具體操作命令的隊列
 * 線程不和任務直接溝通合適傳話人
 */

public class CommandQueueSingleTon {
    private static CommandQueueSingleTon commandQueueSingetion = null;

    //存放命令的隊列 之所以使用linkedlist 因爲命令的讀寫操作頻繁
    Queue<Command> commandQueue = new LinkedList<Command>();

    //1.私有構造
    private CommandQueueSingleTon() {

    }

    //2.對外暴露方法(獲取一個有權限的引用指向這個實例)
    public static CommandQueueSingleTon getQueueSinglton() {
        if (commandQueueSingetion == null) {
            synchronized (CommandQueueSingleTon.class) {
                if (commandQueueSingetion == null) {
                    commandQueueSingetion = new CommandQueueSingleTon();
                }
            }
        }
        return commandQueueSingetion;
    }

    //4.以上是單例的書寫方式 下面就是提供方式讓命令插入隊列和取出隊列
    public void insertCommand(Command cmd) {
        commandQueue.add(cmd);
    }

    public Command getCommand() {

        if (commandQueue != null) {
            Command command = commandQueue.poll();
            return command;
        } else {
            return null;
        }
    }
}
4.main函數中測試,基本流程也是①創建I/O組件;②根據組件創建具體的命令;③命令入隊;④創建兩個線程,從隊列中讀取調用命令:

/**
 * 測試
 */

public class Test {
    public static void main(String[] args) {
        //1.執行命令的控件
        Compent ram = new RAM("RAM");
        Compent diesk = new RAM("Cpu");

        //2.傳話人
        Command ramReadCommand = new RamReadCommand(ram);
        Command ramWriteCommand = new RamWriteCommand(ram);
        Command dieskReadCommand = new DieskReadCommand(diesk);
        Command dieskWritteCommand = new DieskWriteCommand(diesk);

        //3.命令入列
        CommandQueueSingleTon commandQueue = CommandQueueSingleTon.getQueueSinglton();
        commandQueue.insertCommand(ramReadCommand);
        commandQueue.insertCommand(ramWriteCommand);
        commandQueue.insertCommand(dieskReadCommand);
        commandQueue.insertCommand(ramWriteCommand);
        commandQueue.insertCommand(dieskWritteCommand);

        //4。創建線程
        Runnable commandProcessor1 = new CommandProcess();
        Runnable commandProcessor2 = new CommandProcess();

        //start 並不是啓動線程而是代表只是把線程放到cpu執行隊列中
        Thread thread1 = new Thread(commandProcessor1);
        thread1.start();

        Thread thread2 = new Thread(commandProcessor2);
        thread2.start();

    }

    static class CommandProcess implements Runnable {
        @Override
        public void run() {
            while (true) {
                try {
                    //隨機睡上1-4s
                    Random RAND = new Random(1);
                    Thread.sleep(RAND.nextInt(4*1024));

                    CommandQueueSingleTon queueSinglton = CommandQueueSingleTon.getQueueSinglton();
                    Command command = queueSinglton.getCommand();
                    if (command != null) {
                        command.execute();
                    } else {
                        break;
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
ps:這段代碼比較簡單,其中用到的隨機數和僞隨機數的概念在另一篇文章有簡單介紹,線程的介紹也是,大家有需要的話可以自行閱覽。
如果對以上代碼有疑問的話,希望大家能隨時指出。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章