设计模式实例——基于命令模式的事件处理框架

来源:互联网 发布:园林设计效果图软件 编辑:程序博客网 时间:2024/06/05 21:06

在面向对象程序设计中,命令模式是一种很常用的模式。

定义:通常情况下,行为的发送者与接收者之间是一种紧耦合,命令模式就是将一组行为封装成对象,实现二者之间的松耦合。

角色定义:

Command:命令封装对象,可以在其中存储一些有关行为信息和数据。

Invoker:实际的命令发送者,它相当于一个调度中心。

Receiver:事件的接收者,也就是实际做事的那个对象。

Client:客户端,它创建出命令。


今天我们基于命令模式来做一个简单的事件处理模型。总体思路就是用一个队列去保存这些命令,然后有一个线程去检测这个队列,当这个队列中有命令时,则取出来实现它。

首先,我们新建一个Command的接口

public interface ICommand {    void execute();}
然后再定义一个Receiver,实际做工作的那个对象。这个类有两个行为,一个是上传文件,一个是获取网络数据。
public class HttpWorker extends Worker{    public void uploadFile() {        System.out.println("HttpWorker->uploadFile");    }    public void getNetworkData() {        System.out.println("HttpWorker->getNetworkData");    }}


下来为这两个行为定义两个Command,及他们的父类,用来做一些相同的工作

public abstract class HttpCommand implements ICommand{    protected HttpWorker httpWorker;    public HttpCommand() {        super();        httpWorker = new HttpWorker();    }}
public class UploadFileCommand extends HttpCommand {    @Override    public void execute() {        httpWorker.uploadFile();    }}
public class GetNetworkDataCommand extends HttpCommand {    @Override    public void execute() {        httpWorker.getNetworkData();    }}


下来就是消息处理的核心——消息队列
public class EventWorker {    private Queue<ICommand> commandQueue;    private WorkerThread workerThread;    private Object lock;    public void start() {        lock = new Object();        commandQueue = new LinkedBlockingQueue<>();        workerThread = new WorkerThread();        workerThread.start();    }    public void add(ICommand command) {        synchronized (commandQueue) {            System.out.println("add a command");            commandQueue.add(command);            synchronized (lock) {                lock.notify();            }        }    }    public void remove(ICommand command) {        synchronized (commandQueue) {            commandQueue.remove(command);        }    }    public void stop() {        workerThread.setStart(false);        //在停止的时候,有可能工作线程在等待,所以要notify一下        synchronized (lock) {            lock.notify();        }        commandQueue.clear();        commandQueue = null;        workerThread = null;        lock = null;    }    private class WorkerThread extends Thread {        private boolean isStart = false;        public void setStart(boolean b) {            isStart = b;        }        @Override        public synchronized void start() {            isStart = true;            super.start();        }                //这种写法会出现死锁,注意!!!//        public void run() {//            System.out.println("EventWorkerThread work!");//            while(true) {//                synchronized (commandQueue) {//                if(!isStart) break;//                    if(commandQueue.isEmpty()) {//                        System.out.println("queue is empty->wait\n\n");//                        synchronized (lock) {//                            try {//                                lock.wait();//                            } catch (InterruptedException e) {//                                e.printStackTrace();//                            }//                        }//                    } else {////                        ICommand c = commandQueue.poll();//                        if(c != null) {//                            c.execute();//                        }//                    }//                }//            }//            System.out.println("EventWorkerThread stop!");//        }                public void run() {            System.out.println("EventWorkerThread work!");            while(true) {                //如果停止循环则退出                if(!isStart) break;                //线程同步,先获取commandQueue的锁                synchronized (commandQueue) {                    //如果命令队列不为空,则取出顶部的消息                    if(!commandQueue.isEmpty()) {                        ICommand c = commandQueue.poll();                        if(c != null) {                            c.execute();                        }                        //继续循环                        continue;                    }                }                //如果队列为空,是进行等待                synchronized (lock) {                    try {                        System.out.println("queue is empty->wait\n\n");                        lock.wait();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }            System.out.println("EventWorkerThread stop!");        }    }}

上面主要的代码都做了注释,大家都能看懂它的工作原理。就是做一个队列,然后有一个线程不停的去检测这个队列,如果有命令就执行,反之,等待。当添加一个命令时,则notify检测线程继续工作。

在多线程中,一定要注意线程的同步,否则会出现脏数据,还有就是锁的运用,不然会出现死锁等一些问题,而且这些问题都不容易查出来,所以在多个线程操作同一个数据时一定要加锁。

下来就是客户端对象,客户端是创建命令的地方。

public class Client {    public static void main(String[] args) throws InterruptedException {        EventWorker eventWorker = new EventWorker();        eventWorker.start();        ICommand uploadFileCommand = new UploadFileCommand();        ICommand getNetworkDataCommand = new GetNetworkDataCommand();        Thread.sleep(3000);        for(int i = 0; i < 10; i++) {            if(i % 2 == 0) {                eventWorker.add(uploadFileCommand);            } else {                eventWorker.add(getNetworkDataCommand);            }            Thread.sleep(2000);        }        eventWorker.stop();    }}


好了,这个框架就算大概完成了,这只是一个很简单的例子,在实际工作中,可能要比这复杂的多。运用模式可以使我们的代码更加高效和可维护,但是也不要滥用模式,23种设计模式没有谁好谁坏,适合的才是最好的。



1 0
原创粉丝点击