java命令模式的实际应用
来源:互联网 发布:seo如何发外链 编辑:程序博客网 时间:2024/06/04 19:03
java在实际该项目中,用户会进行各种各样的请求操作,现对该问题处理方法进行探讨。
if-else语句或者switch-case语句
具体内容
在实际开发项目中对要功能模块进行管理,通过对输入的某个值的判断确定用户想要做什么,比如输入1表示做事件1,输入2表示做事件2.传统的实现方式可用if-else或者switch-case语句来完成。
相关代码
//if-else语句下的处理方式//表示用户的请求int cmd=1;if(cmd==1){ //做事件1}else if(cmd==2){ //做事件2}//其他
//switch-case语句下的处理方式switch (cmd) {case 1:{ //做事件1 break;}case 2:{ //做事件2 break;}default://........ break;}
评价
该方法是一般最初能想到的也是最直接的方法,但此方法存在一下缺陷。
- 没有体现出面向对象的特征。
- 会增大编程复杂度,降低程序的可读性,如果功能过多,则处理语句会很长。
- 降低程序的性能:运行相对靠后的代码块时必须把前面的判断也访问到,增加了运行时间。
- 增大开发维护的成本:如果要增加一个功能,必须到源代码中去寻找,修改也要在源代码中去修改。而在实际项目中修改源代码是不好的。
命令模式的搭建
以上论述了用if-else,swithc-case语句会的缺点,改造可采用命令模式。
命令模式主要有一下三个要素
1. 命令接口
2. 命令实现类
3. 命令处理器
命令接口
命令接口
为了体现面向对象的抽象性,以及接口和实现分离的原则,对处理事件的过程分装为一个抽象的接口,定义如下。
@FunctionalInterfacepublic interface Command { /** * 命令处理接口 * @param obj 处理数据 * @return 处理结果 */ Object handle(Object obj);}
传入一个Object类型参数,得到返回结果,具体的过程由实现类自己实现。
命令实现类
有了接口就要有实现该接口的具体类,下面举两个例子。
/** * 实现功能:打印传入的参数 * */public class Print implements Command { @Override public Object handle(Object obj) { System.out.println("你传入的是:"+obj); return null; }}
/** * 实现功能 :输出一句话"什么也不做" * */public class None implements Command { @Override public Object handle(Object obj) { System.out.println("什么也不做"); return null; }}
命令处理器
有了接口和实现类,下面要做的就是建立一个类来处理该接口,要想实现对应的功能,必须要知道Command接口对应的是哪个类的对象,为此传入一个String类型表示类名的参数,并通过反射来获取该类的对象。
public class CommandHandler { /** * 处理数据的方法 * @param className 类名 * @param obj 处理数据 * @return 结果 */ public static Object handle(String className,Object obj) { try { //加载对应的Command实现类的对象 Command c=(Command) Class.forName(className).newInstance(); return c.handle(obj); } catch (Exception e){ } return null; }}
这里将处理方法设为公开静态方便调用,传入类名和具体数据,通过反射机制加载Class对象,并生成具体对象并转为Command类型,这里任何异常都不处理,最后通过Command对象调用方法返回结果。
现在可以进行简单的测试
public class Main { public static void main(String[] args) { CommandHandler.handle("Print", "123"); CommandHandler.handle("None", "123"); }}
测试结果
至此,命令模式的基本框架基本搞定,但该方法存在许多问题,将在下面的叙述中进行优化。
命令模式的优化
使用xml文档
使用xml文档的必要性
1.以上通过反射来加载类,我们发现每次都要进行反射获取Class对象并且调用newInstance()方法生成一个对象,实际上我们只需要对应的方法即可,无须每次都要加载。
2.每次传入的参数中必须包含一个类的全类名,这样对用户来说不是很方便。
基于此,我们可以将所有要加载的类名事先写入xml文档,在程序初始化时读取文件,把所有的类名全部获取一个Command对象并保存,用对应的字符串作为关键字进行hash存取,这里的字符串即可当作用户输入的代表命令的字符串。
xml文档需要命令字符串和类名,可按一下格式定义,也可以自己定义。关于xml文档的知识这里不再详述。
<command> <name></name> <classname></classname></command>
继续拿本前面的程序来说明,我们可以建立如下的文档
<?xml version="1.0" encoding="utf-8"?><body> <command> <name>1</name> <classname>Print</classname> </command> <command> <name>2</name> <classname>None</classname> </command></body>
用map进行保存
/**命令集到命令对象的映射*/private static HashMap<String, Command> commands;
初始化时加载该xml文档,把数据读入到commands中
/** * 加载该类时完成对commands的初始化 */ static { // 标志 超时则退出 int flag = 0; while (flag < 5) { try { // 定义文档解析器 DocumentBuilder buidler = DocumentBuilderFactory.newInstance() .newDocumentBuilder(); // 获取解析后的文档对象 Document doc = buidler.parse("main.xml"); // 获取根部元素 Element root = doc.getDocumentElement(); // 加载命令 commands = new HashMap<String, Command>(root.getChildNodes() .getLength()*2+1); // 读取每个结点 for (int i = 0; i < root.getChildNodes().getLength(); i++) { Node e = root.getChildNodes().item(i); // 找到command结点 if (e instanceof Element) { Element elem = (Element) e; if ("command".equals(elem.getNodeName())) { NodeList nl = elem.getChildNodes(); // 处理每个command节点 String name = null, classname = null; for (int j = 0; j < nl.getLength(); j++) { Node n = nl.item(j); if (n instanceof Element) { Element elem1 = (Element) n; // 获取name值 if ("name".equals(elem1.getTagName())) { name = ((Text) elem1.getFirstChild()) .getData().trim(); } // 获取classname值 else if ("classname".equals(elem1 .getTagName())) { classname = ((Text) elem1 .getFirstChild()).getData(); } } } // 把结果加入集合中 if (name != null && classname != null) { //加载Command命令 Command c = (Command) Class.forName(classname).newInstance(); //放入集合中 commands.put(name, c); } } } } break; } catch (Exception e) { flag++; // 设置超过五次则系统停止 if (flag == 5) { System.out.println("命令系统异常"); //退出系统 System.exit(-1); } } } if(commands==null) { System.out.println("命令系统异常"); //退出系统 System.exit(-1); } }
处理方法的代码优化
/** * 处理数据的方法 * @param cmd 命令字符串 * @param obj 处理数据 * @return 结果 */ public static Object handle(String cmd,Object obj) { try { //查找map 获取对应的Command实现类的对象 return commands.get(cmd).handle(obj); } catch (Exception e){ } return null; }
测试代码
public static void main(String[] args) { //1对应的是打印 CommandHandler2.handle("1", "123"); //2对应什么也不做 CommandHandler2.handle("2", "123"); //3无效 CommandHandler2.handle("3", "123"); }
测试结果
这样,只要传入一个命令字符串即可,无须传入类名,每个类也只会加载一次生成一个对象。当需要添加一个命令时,只需添加一个类实现Command接口,并且完成未实现的方法,再把命令字符串和类名在xml文档中进行注册即可。
自定义Message对象
在实际开发中,这样传入参数还是有些麻烦,而且用户很多时候用户有多个请求时间,所以这样的结构还是有些问题,我们在这里定义一个Message对象分装用户的所有请求,本质上是一个个的命令字符串到数据的键对,这里用map存取。
public final class Message { /**表示信息的集合*/ private Map<String,Object> msg=new HashMap<String, Object>(); /** * 添加一条信息 * @param str 信息对应指令 * @param obj 信息内容 */ public void put(String str,Object obj) { msg.put(str, obj); } /** * 判断消息为空 * @return true表示消息为空 false 表示有内容 */ public boolean isEmpty() { return msg.isEmpty(); } /** * 获取信息长度 * @return 信息长度 */ public int Size() { return msg.size(); } /** * 根据指令获得信息内容 * @param str 指令 * @return 信息内容 */ public Object getParameter(String str) { return msg.get(str); } /** * * @return 命令字符串集 */ public Set<String> KetSet() { return msg.keySet(); }}
修改处理的方法
/** * 处理数据的方法 * @param message 处理信息 * @return 结果 */ public static Message handle(Message message) { Message r=new Message(); try { for(String e:message.KetSet()) { //获取每个命令和对应数据 并获得结果 r.put(e, commands.get(e).handle(message.getParameter(e))); } } catch (Exception e){ } return r; }
测试
public static void main(String[] args) { //生成一个Message Message message=new Message(); message.put("1", "123"); message.put("2", "123"); message.put("3", "123"); CommandHandler3.handle(message);}
测试结果
- java命令模式的实际应用
- JAVA中设计模式的实际应用
- killall命令的实际应用
- scp命令的实际应用
- 设计模式的实际应用
- 设计模式的实际应用
- 探讨Java代理模式与反射机制的实际应用
- Java实际应用中经常遇到的"装饰模式"总结
- Java中抽象类的实际应用:模板设计模式
- MySQL数据库备份的命令实际应用
- 接口的实际应用--工厂设计模式
- 接口的实际应用--代理设计模式
- 接口的实际应用--适配器模式
- 生产者消费者模式的一次实际应用
- Java静态内部类的实际应用
- java 单例的实际应用
- Java注解的实际应用案例讲解
- java枚举的实际应用案例
- Java中由Calendar类获取的月、天和小时的简单处理
- 产品经理成长之路(一)
- 一个老鸟发的公司内部整理的 Android 学习路线图 Markdown 版本
- NFile——基于Nodejs的文件系统
- 《iOS移动开发从入门到精通》图书连载12:元组类型、一元、二元和三元运算符、 比较运算符
- java命令模式的实际应用
- epoll总结
- HDU 2853 Assignment(最佳二分图匹配)
- 如何在Matlab中获取函数参数的数目?
- eclipse远程debug服务器项目
- USRP_N210R4 verilog代码分析一:gpio_atr模块
- Java知识点列表
- 【数据库SQL】批量更新促发器游标的方法
- R语言:用微软的深度学习理解图片情感