美文网首页奔跑吧,JAVA!Android高级技术软件生涯
Android 架构师之路11 设计模式之命令模式

Android 架构师之路11 设计模式之命令模式

作者: 香沙小熊 | 来源:发表于2018-01-27 11:25 被阅读180次

    Android 架构师之路 目录

    1、命令模式概念

    1.1 介绍

    命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。

    1.2 定义

    将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或记录请求日志。以及支持可撤销的操作。

    1.3 使用场景
    • 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
    • 系统需要在不同的时间指定请求、将请求排队(如:线程池+工作队列)和执行请求。
    • 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
    • 系统需要将一组操作组合在一起,即支持宏命令。

    2、命令模式UML类图

    命令模式UML类图
    • Command(抽象命令类):抽象出命令对象,可以根据不同的命令类型。写出不同的实现类

    • ConcreteCommand(具体命令类):实现了抽象命令对象的具体实现

    • Invoker(调用者/请求者):请求的发送者,它通过命令对象来执行请求。一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令来之间存在关联。在程序运行时,将调用命令对象的execute() ,间接调用接收者的相关操作。

    • Receiver(接收者):接收者执行与请求相关的操作,真正执行命令的对象。具体实现对请求的业务处理。未抽象前,实际执行操作内容的对象。

    • Client(客户端):在客户类中需要创建调用者对象,具体命令类对象,在创建具体命令对象时指定对应的接收者。发送者和接收者之间没有之间关系,都通过命令对象来调用。

    3、命令模式代码实现

    俄罗斯方块游戏
    向下方块、向右方块、向左方块...,每一个方向都是一个命令

    Command:
    public interface ICommand extends Serializable {
        void execute();
    }
    
    ConcreteCommand:
    public class LeftCommand implements ICommand {
        private Receiver receiver;
        public LeftCommand(Receiver receiver) {
            this.receiver = receiver;
        }
        @Override
        public void execute() {
            /**
             * 执行之前干一些事情
             *  例如 存档
             */
            this.receiver.onLeft();
        }
    }
    
    
    public class RightCommand implements ICommand {
        private Receiver receiver;
        public RightCommand(Receiver receiver) {
            this.receiver = receiver;
        }
        @Override
        public void execute() {
            this.receiver.onRight();
        }
    
    }
    
    
    
    public class BottomCommand implements ICommand {
        private Receiver receiver;
        public BottomCommand(Receiver receiver) {
            this.receiver = receiver;
        }
        @Override
        public void execute() {
            this.receiver.onBottom();
        }
    }
    
    
    public class TransfromCommand implements ICommand {
        private Receiver receiver;
    
        public TransfromCommand(Receiver receiver) {
            this.receiver = receiver;
        }
    
        @Override
        public void execute() {
            this.receiver.onTransformation();
        }
    
    
    }
    
    Invoker:
    public class Invoker {
        private ICommand leftCommand;
        private ICommand rightCommand;
        private ICommand bottomCommand;
        private ICommand transfromCommand;
        private List<ICommand> commandList = new ArrayList<>();
    
        public Invoker() {
        }
    
        public Invoker(ICommand leftCommand, ICommand rightCommand, ICommand bottomCommand, ICommand transfromCommand) {
            this.leftCommand = leftCommand;
            this.rightCommand = rightCommand;
            this.bottomCommand = bottomCommand;
            this.transfromCommand = transfromCommand;
        }
    
        public void toLeft() {
            this.leftCommand.execute();
            commandList.add(leftCommand);
        }
    
        public void toRight() {
            this.rightCommand.execute();
            commandList.add(rightCommand);
        }
    
        public void toBottom() {
            this.bottomCommand.execute();
            commandList.add(bottomCommand);
        }
    
        public void toTransfrom() {
            this.transfromCommand.execute();
            commandList.add(transfromCommand);
        }
    
        /**
         * 回退
         */
        public void fallback() {
            if (commandList.size() > 0) {
                commandList.remove(commandList.size() - 1);
            }
        }
    
        /**
         * 存档
         */
        public void saveArchive() {
            Utils.serializable("gameOperation", commandList);
        }
    
        /**
         * 读档
         */
        public void loadArchive() {
            List<ICommand> list = Utils.deserialize("gameOperation");
            this.commandList.clear();
            this.commandList.addAll(list);
            for (ICommand command : list) {
                command.execute();
            }
        }
    }
    
    Receiver:
    public class Receiver implements Serializable {
    
        public void onLeft() {
            System.out.println("向左");
        }
    
        public void onRight() {
            System.out.println("向右");
        }
    
        public void onBottom() {
            System.out.println("向下");
        }
    
        public void onTransformation() {
            System.out.println("变形");
        }
    }
    
    存档、读档工具类:
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.util.List;
    
    
    public class Utils {
        /**
         * 序列化订单对象
         */
        public static void serializable(String name,
                                        List<ICommand> commandList) {
            // 序列化对象的流
            ObjectOutputStream outputStream = null;
            try {
                outputStream = new ObjectOutputStream(new FileOutputStream(
                        new File("C:\\Users\\Administrator\\Desktop\\" + name + ".txt")));
                outputStream.writeObject(commandList);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (outputStream != null) {
                    try {
                        outputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        public static List<ICommand> deserialize(String name) {
            ObjectInputStream objectInputStream = null;
            try {
                objectInputStream = new ObjectInputStream(new FileInputStream(
                        new File("C:\\Users\\Administrator\\Desktop\\"
                                + name + ".txt")));
                Object readObject = objectInputStream.readObject();
                return (List<ICommand>) readObject;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    
    Client :
    public class Client {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            /**
             * 接收者
             */
            Receiver receiver = new Receiver();
    
            // 命令对象
            ICommand leftCommand = new LeftCommand(receiver);
            ICommand rightCommand = new RightCommand(receiver);
            ICommand bottomCommand = new BottomCommand(receiver);
            ICommand transfromCommand = new TransfromCommand(receiver);
    
            //请求者
            Invoker invoker = new Invoker(leftCommand, rightCommand, bottomCommand, transfromCommand);
            invoker.toLeft();
            invoker.toRight();
            invoker.toBottom();
            invoker.toTransfrom();
    
            //序列化存档
            System.out.println("----存档----");
            invoker.saveArchive();
    
            invoker.toBottom();
    
    
            System.out.println("----读档----");
            //读档
            invoker.loadArchive();
        }
    }
    

    结果输出:

    向左
    向右
    向下
    变形
    ----存档----
    向下
    ----读档----
    向左
    向右
    向下
    变形
    

    4、命令模式Android中使用

    IHttpCommand相当于命令接口Command:
    /**
     * 网络请求命令接口
     *
     * 以前采用Map集合传入, 现在面向接口编程
     * Created by Xionghu on 2017/7/4.
     * Desc:
     */
    
    public interface IHttpCommand<T extends IRequestParam> {
        public enum RequestType {
            Default(0), Get(1), Post(2), Delete(3);
            private int type;
    
            private RequestType(int type) {
                this.type = type;
            }
    
            public int getType() {
                return type;
            }
        }
    
        public String execute(Context context, String url, RequestType requestType,
                              T requestParam);
    }
    
    SystemHttpCommand 相当于具体命令实现ConcreteCommand:.
    OKHttpCommand 省略
    public class SystemHttpCommand extends AbsHttpCommand<SystemRequestParam> {
        @Override
        public String executePost(Context context, String url, SystemRequestParam requestParam) {
            //发送请求
            try {
                return HttpUtils.post(url, requestParam.getRequestParam());
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        @Override
        public String executeGet(Context context, String url, SystemRequestParam requestParam) {
            try {
                return HttpUtils.get(url,requestParam.getRequestParam());
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    
    HttpUtils 相当于接收者Receiver:
    public class HttpUtils {
    
        public static String get(String urlStr, Map<String, Object> paramMap)
                throws Exception {
            // 拼接参数
            StringBuilder params = new StringBuilder(urlStr + "?");
            int i = 0;
            for (String key : paramMap.keySet()) {
                Object value = paramMap.get(key);
                params.append(key);
                params.append("=");
                params.append(value);
                if (i < paramMap.size() - 1) {
                    params.append("&");
                }
                i++;
            }
            return get(params.toString());
        }
    
        public static String get(String urlStr) {
            String result = null;
            try {
                URL url = new URL(urlStr);
                HttpURLConnection connection = (HttpURLConnection) url
                        .openConnection();
                connection.setReadTimeout(5000);
                connection.setRequestMethod("GET");
                connection.setDoInput(true);
                if (connection.getResponseCode() == 200) {
                    InputStream inStream = connection.getInputStream();
                    result = new String(StreamTool.readInputStream(inStream));
                    return result;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        }
    
        public static String post(String urlStr, String username, String password)
                throws Exception {
            Map<String, Object> paramMap = new HashMap<String, Object>();
            paramMap.put("username", username);
            paramMap.put("password", password);
            return post(urlStr, paramMap);
        }
    
        public static String post(String urlStr, Map<String, Object> paramMap)
                throws Exception {
            StringBuffer sb = null;
            // 拼接参数
            StringBuilder params = new StringBuilder();
            int i = 0;
            for (String key : paramMap.keySet()) {
                Object value = paramMap.get(key);
                params.append(key);
                params.append("=");
                params.append(value);
                if (i < paramMap.size() - 1) {
                    params.append("&");
                }
                i++;
            }
            // 创建请求地址
            URL url = new URL(urlStr);
            // 打开连接
            HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
            // 设置参数
            httpConn.setDoOutput(true); // 需要输出
            httpConn.setDoInput(true); // 需要输入
            httpConn.setUseCaches(false); // 不允许缓存
            httpConn.setRequestMethod("POST"); // 设置POST方式连接
            // 设置请求属性
            httpConn.setRequestProperty("Charset", "UTF-8");
            // 连接,也可以不用明文connect,使用下面的httpConn.getOutputStream()会自动connect
            httpConn.connect();
            // 建立输入流,向指向的URL传入参数
            DataOutputStream dos = new DataOutputStream(httpConn.getOutputStream());
            dos.writeBytes(params.toString());
            dos.flush();
            dos.close();
            // 获得响应状态
            int resultCode = httpConn.getResponseCode();
            sb = new StringBuffer();
            if (HttpURLConnection.HTTP_OK == resultCode) {
                // 解析服务器返回的数据
                String readLine = new String();
                BufferedReader responseReader = new BufferedReader(
                        new InputStreamReader(httpConn.getInputStream(), "UTF-8"));
                while ((readLine = responseReader.readLine()) != null) {
                    sb.append(readLine).append("\n");
                }
                responseReader.close();
                return sb.toString();
            }
            return null;
        }
    
        public interface OnHttpResultListener {
            public void onResult(String result);
        }
    }
    
    HttpTask 相当于请求者Invoker
    
    public class HttpTask extends AsyncTask<String, Void, String> {
    
        private HttpTask.Builder.Params p;
    
        protected HttpTask(HttpTask.Builder.Params p) {
            this.p = p;
        }
    
        @SuppressWarnings("unchecked")
        @Override
        protected String doInBackground(String... params) {
            try {
                // 执行命令
                return this.p.httpCommand.execute(this.p.context, this.p.url,
                        this.p.requestType, this.p.requestParam);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        @Override
        protected void onPostExecute(String result) {
            if (this.p.onHttpResultListener != null) {
                this.p.onHttpResultListener.onResult(result);
            }
        }
    
        public void builder() {
            execute();
        }
    
        // 采用Builder设计模式
        public static class Builder {
    
            private Params p;
    
            public Builder(Context context, String url,
                           HttpUtils.OnHttpResultListener onHttpResultListener) {
                this.p = new Params(context, url, onHttpResultListener);
            }
    
            public Builder setRequestType(IHttpCommand.RequestType requestType) {
                this.p.requestType = requestType;
                return this;
            }
    
            public Builder setRequestParam(IRequestParam requestParam) {
                this.p.requestParam = requestParam;
                return this;
            }
    
            public Builder setHttpCommand(IHttpCommand httpCommand) {
                this.p.httpCommand = httpCommand;
                return this;
            }
    
            public HttpTask build() {
                return new HttpTask(p);
            }
    
            public static class Params {
                public Context context;
                public IHttpCommand.RequestType requestType;
                public String url;
                public IRequestParam requestParam;
                public HttpUtils.OnHttpResultListener onHttpResultListener;
                public IHttpCommand httpCommand;
    
                public Params(Context context, String url,
                              HttpUtils.OnHttpResultListener onHttpResultListener) {
                    this.context = context;
                    this.url = url;
                    this.requestType = IHttpCommand.RequestType.Get;
                    this.httpCommand = new SystemHttpCommand();
                    this.requestParam = new SystemRequestParam();
                    this.onHttpResultListener = onHttpResultListener;
                }
            }
    
        }
    
    }
    
    Client :
            //请求者
            HttpTask.Builder builder = new HttpTask.Builder(this, "", new HttpUtils.OnHttpResultListener() {
                @Override
                public void onResult(String result) {
    
                }
            });
    
            IRequestParam requestParam = new SystemRequestParam();
            requestParam.put("","");
            builder.setRequestParam(requestParam)
                   .setRequestType(IHttpCommand.RequestType.Post)
                   .build()
                   .builder();
    
          //请求者
            HttpTask.Builder builder = new HttpTask.Builder(this, "", new HttpUtils.OnHttpResultListener() {
                @Override
                public void onResult(String result) {
    
                }
            });
            IRequestParam requestParam = new OKHttpRequestParam();
            requestParam.put("","");
            builder.setRequestParam(requestParam)
                    .setHttpCommand(new OKHttpCommand())
                    .setRequestType(IHttpCommand.RequestType.Post).build().builder();
    

    整个网络请求架构采用了命令模式
    使我们得程序扩展性更加好,耦合降低了(比如 添加setHttpCommand 设置okhttp请求很方便)

    5、模式总结

    5.1 优点
    • 解除了请求者与实现者之间的耦合,降低了系统的耦合度。

    • 对请求排队或记录请求日志,支持撤销操作。

    • 可以容易地设计一个组合命令。

    • 新命令可以容易地加入到系统中。

    5.2 缺点
    • 因为针对每一个命令都需要设计一个具体命令类,使用命令模式可能会导致系统有过多的具体命令类。

    相关文章

      网友评论

        本文标题:Android 架构师之路11 设计模式之命令模式

        本文链接:https://www.haomeiwen.com/subject/zixnaxtx.html