设计模式示例_命令设计模式示例
設計模式示例
本文是我們名為“ Java設計模式 ”的學院課程的一部分。
 在本課程中,您將深入研究大量的設計模式,并了解如何在Java中實現和利用它們。 您將了解模式如此重要的原因,并了解何時以及如何應用模式中的每一個。 在這里查看 ! 
目錄
1.簡介 2.什么是命令設計模式 3.實施命令設計模式 4.何時使用命令設計模式 5. JDK中的命令設計模式 6.下載源代碼1.簡介
命令設計模式是一種行為設計模式,有助于將調用者與請求的接收者解耦。
為了理解命令設計模式,讓我們創建一個示例來執行不同類型的作業。 作業可以是系統中的任何內容,例如,發送電子郵件,SMS,日志記錄以及執行某些IO功能。
命令模式將有助于將調用者與接收者解耦,并有助于執行任何類型的作業,而無需了解其實現。 讓我們通過創建線程來幫助并發執行這些作業,使該示例更加有趣。 由于這些作業彼此獨立,因此這些作業的執行順序并不是很重要。 我們將創建一個線程池以限制執行作業的線程數。 命令對象將封裝作業,并將其從執行作業的池中移交給線程。
在實施示例之前,讓我們進一步了解命令設計模式。
2.什么是命令設計模式
命令設計模式的目的是將請求封裝為對象,從而使開發人員可以將具有不同請求,隊列或日志請求的客戶端參數化,并支持可撤銷的操作。
通常,面向對象的應用程序由一組交互對象組成,每個對象都提供有限的集中功能。 響應于用戶交互,應用程序執行某種處理。 為此,應用程序將不同對象的服務用于處理需求。
在實現方面,應用程序可能依賴于通過將所需數據作為參數傳遞來調用這些對象上的方法的指定對象。 這個指定的對象可以稱為調用程序,因為它調用不同對象上的操作。 調用方可以視為客戶端應用程序的一部分。 實際包含提供請求處理所需服務的實現的對象集可以稱為Receiver對象。
使用命令模式,可以分離代表客戶端發出請求的調用方和一組服務呈現Receiver對象。 命令模式建議為響應客戶請求而執行的處理或要采取的動作創建一個抽象。 可以將這種抽象設計為聲明要由不同的具體實現者(稱為Command對象)實現的公共接口。 每個Command對象代表不同類型的客戶端請求和相應的處理。
給定的Command對象負責提供處理它所代表的請求所需的功能,但是它不包含該功能的實際實現。 Command對象在提供此功能時利用了Receiver對象。
圖1 –命令模式類圖
命令
- 聲明用于執行操作的接口。
具體命令
- 定義Receiver對象和操作之間的綁定。
- 通過在Receiver上調用相應的操作來實現Execute 。
客戶
- 創建一個ConcreteCommand對象并設置其接收者。
召喚者
- 要求命令執行請求。
接收者
- 知道如何執行與執行請求相關的操作。 任何類都可以充當Receiver 。
3.實施命令設計模式
我們將使用命令對象來實現示例。 該命令對象將由通用接口引用,并將包含用于執行請求的方法。 具體的命令類將覆蓋該方法,并將提供其自己的特定實現以執行請求。
package com.javacodegeeks.patterns.commandpattern;public interface Job {public void run(); }Job接口是命令接口,包含單個方法run ,該方法由線程執行。 我們命令的execute方法是run方法,該方法將由線程執行以完成工作。
可以執行不同類型的作業。 以下是不同的具體類,它們的實例將由不同的命令對象執行。
package com.javacodegeeks.patterns.commandpattern;public class Email {public void sendEmail(){System.out.println("Sending email.......");} }package com.javacodegeeks.patterns.commandpattern;public class FileIO {public void execute(){System.out.println("Executing File IO operations...");} }package com.javacodegeeks.patterns.commandpattern;public class Logging {public void log(){System.out.println("Logging...");} }package com.javacodegeeks.patterns.commandpattern;public class Sms {public void sendSms(){System.out.println("Sending SMS...");} }以下是封裝以上類并實現Job接口的不同命令類。
package com.javacodegeeks.patterns.commandpattern;public class EmailJob implements Job{private Email email;public void setEmail(Email email){this.email = email;}@Overridepublic void run() {System.out.println("Job ID: "+Thread.currentThread().getId()+" executing email jobs.");if(email!=null){email.sendEmail();}try {Thread.sleep(1000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}}}package com.javacodegeeks.patterns.commandpattern;public class FileIOJob implements Job{private FileIO fileIO;public void setFileIO(FileIO fileIO){this.fileIO = fileIO;}@Overridepublic void run() {System.out.println("Job ID: "+Thread.currentThread().getId()+" executing fileIO jobs.");if(fileIO!=null){fileIO.execute();}try {Thread.sleep(1000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}} }package com.javacodegeeks.patterns.commandpattern;public class LoggingJob implements Job{private Logging logging;public void setLogging(Logging logging){this.logging = logging;}@Overridepublic void run() {System.out.println("Job ID: "+Thread.currentThread().getId()+" executing logging jobs.");if(logging!=null){logging.log();}try {Thread.sleep(1000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}} }package com.javacodegeeks.patterns.commandpattern;public class SmsJob implements Job{private Sms sms;public void setSms(Sms sms) {this.sms = sms;}@Overridepublic void run() {System.out.println("Job ID: "+Thread.currentThread().getId()+" executing sms jobs.");if(sms!=null){sms.sendSms();}try {Thread.sleep(1000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}}}上面的類引用了各自的類,這些類將用于完成工作。 這些類將覆蓋run方法并執行請求的工作。 例如, SmsJob類用于發送短信,其運行方法調用Sms對象的sendSms方法以完成工作。
您可以將一個不同的對象一一設置到同一command對象。
下面是ThreadPool類,該類用于創建線程池并允許線程從作業隊列中獲取并執行作業。
package com.javacodegeeks.patterns.commandpattern;import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue;public class ThreadPool {private final BlockingQueue<Job> jobQueue;private final Thread[] jobThreads;private volatile boolean shutdown;public ThreadPool(int n){jobQueue = new LinkedBlockingQueue<>();jobThreads = new Thread[n];for (int i = 0; i < n; i++) {jobThreads[i] = new Worker("Pool Thread " + i);jobThreads[i].start();}}public void addJob(Job r){try {jobQueue.put(r);} catch (InterruptedException e) {Thread.currentThread().interrupt();}}public void shutdownPool(){while (!jobQueue.isEmpty()) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}shutdown = true;for (Thread workerThread : jobThreads) {workerThread.interrupt();}}private class Worker extends Thread{public Worker(String name){super(name);}public void run(){while (!shutdown) {try {Job r = jobQueue.take();r.run();} catch (InterruptedException e) {}}}}}上面的類用于創建n個線程(工作線程)。 每個工作線程將在隊列中等待作業,然后執行該作業,并返回到等待狀態。 該類包含一個作業隊列。 當將新作業添加到隊列中時,池中的工作線程將執行該作業。
我們還包括一個shutdownPool方法,該方法僅在作業隊列為空時才通過中斷所有工作線程來關閉池。 addJob方法用于將作業添加到隊列。
現在,讓我們測試代碼。
package com.javacodegeeks.patterns.commandpattern;public class TestCommandPattern {public static void main(String[] args){init();}private static void init(){ThreadPool pool = new ThreadPool(10);Email email = null;EmailJob emailJob = new EmailJob();Sms sms = null;SmsJob smsJob = new SmsJob();FileIO fileIO = null;;FileIOJob fileIOJob = new FileIOJob();Logging logging = null;LoggingJob logJob = new LoggingJob();for (int i = 0; i < 5; i++) {email = new Email();emailJob.setEmail(email);sms = new Sms();smsJob.setSms(sms);fileIO = new FileIO();fileIOJob.setFileIO(fileIO);logging = new Logging();logJob.setLogging(logging);pool.addJob(emailJob);pool.addJob(smsJob);pool.addJob(fileIOJob);pool.addJob(logJob);}pool.shutdownPool();}}上面的代碼將導致以下輸出:
Job ID: 9 executing email jobs. Sending email....... Job ID: 12 executing logging jobs. Job ID: 17 executing email jobs. Sending email....... Job ID: 13 executing email jobs. Sending email....... Job ID: 10 executing sms jobs. Sending SMS... Job ID: 11 executing fileIO jobs. Executing File IO operations... Job ID: 18 executing sms jobs. Sending SMS... Logging... Job ID: 16 executing logging jobs. Logging... Job ID: 15 executing fileIO jobs. Executing File IO operations... Job ID: 14 executing sms jobs. Sending SMS... Job ID: 12 executing fileIO jobs. Executing File IO operations... Job ID: 10 executing logging jobs. Logging... Job ID: 18 executing email jobs. Sending email....... Job ID: 16 executing sms jobs. Sending SMS... Job ID: 14 executing fileIO jobs. Executing File IO operations... Job ID: 9 executing logging jobs. Logging... Job ID: 17 executing email jobs. Sending email....... Job ID: 13 executing sms jobs. Sending SMS... Job ID: 15 executing fileIO jobs. Executing File IO operations... Job ID: 11 executing logging jobs. Logging...請注意,輸出在后續執行中可能會有所不同。
在上面的類中,我們創建了一個具有10個線程的線程池。 然后,我們使用不同的作業設置不同的命令對象,并使用ThreadPool類的addJob方法將這些作業添加到隊列中。 作業插入隊列后,線程就會執行該作業并將其從隊列中刪除。
我們設置了不同類型的作業,但是通過使用命令設計模式,我們將作業與調用程序線程解耦。 線程將執行實現Job接口的任何類型的對象。 不同的命令對象封裝了不同的對象,并在這些對象上執行了請求的操作。
輸出顯示執行不同作業的不同線程。 通過查看輸出中的作業ID,您可以清楚地看到一個線程正在執行多個作業。 這是因為執行作業后,線程將發送回池中。
命令設計模式的優點是您可以添加更多不同種類的作業,而無需更改現有類。 這樣可以帶來更大的靈活性和可維護性,并減少代碼中出現錯誤的機會。
4.何時使用命令設計模式
當您要執行以下操作時,請使用“命令”模式:
- 通過要執行的操作對對象進行參數化。
- 在不同時間指定,排隊和執行請求。 Command對象的生存期可以獨立于原始請求。 如果可以以與地址空間無關的方式表示請求的接收者,則可以將請求的命令對象傳輸到其他進程并在那里執行請求。
- 支持撤消。 命令的Execute操作可以在命令本身中存儲狀態以反轉其效果。 Command界面必須具有添加的Un-execute操作,該操作可以逆轉先前對Execute的調用的效果。 執行的命令存儲在歷史列表中。 通過向后遍歷此列表并向前調用Un-execute和Execute來實現無限級撤消和重做。
- 支持日志記錄更改,以便在系統崩潰時可以重新應用它們。 通過使用加載和存儲操作擴展Command界面,您可以保留更改的持久日志。 從崩潰中恢復涉及從磁盤重新加載記錄的命令,并使用Execute操作重新執行它們。
- 圍繞基于原始操作的高級操作構建系統。 這種結構在支持交易的信息系統中很常見。 事務封裝了一組數據更改。 命令模式提供了一種對事務進行建模的方法。 命令具有公共接口,可讓您以相同的方式調用所有事務。 該模式還使通過新事務輕松擴展系統成為可能。
5. JDK中的命令設計模式
- java.lang.Runnable
- javax.swing.Action
6.下載源代碼
這是有關命令設計模式的課程。 您可以在此處下載源代碼: CommandPattern-Project
翻譯自: https://www.javacodegeeks.com/2015/09/command-design-pattern.html
設計模式示例
總結
以上是生活随笔為你收集整理的设计模式示例_命令设计模式示例的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 电脑设置远程控制的方法如何让电脑远程
- 下一篇: 大手玩家的最佳无线鼠标适合大手用的无线鼠
