Java使用builder模式+注解实现命令模式
业务场景:
项目中需要对数据进行异步分发推送,由于业务类型比较多,又考虑到不能影响现有的功能和代码耦合问题,所以考虑了一下设计模式;
好处:代码耦合度低,便于命令集的管理以及统一事件的处理,异步执行,不影响原有的业务;
缺点:没有考虑线程池的策略问题,需要自己定义(可以考虑如果线程达到最大限度后由原有的线程处理自己的业务或是加入队列机制、开启新的线程去监听队列并执行)
1、新建注解类
1 package com.test.util.Broker; 2 3 import java.lang.annotation.Retention; 4 import java.lang.annotation.RetentionPolicy; 5 import java.lang.annotation.Target; 6 7 @Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.TYPE}) 8 @Retention(RetentionPolicy.RUNTIME) 9 public @interface CommandBroker { 10 BrokerFactory.CommandEnum command() default BrokerFactory.CommandEnum.NONE; 11 }
2、新建BrokerFactory类
1 package com.test.util.Broker; 2 3 import org.slf4j.Logger; 4 import org.slf4j.LoggerFactory; 5 6 import java.lang.reflect.Method; 7 import java.util.concurrent.ExecutorService; 8 import java.util.concurrent.Executors; 9 10 public class BrokerFactory { 11 private final static Logger logger = LoggerFactory.getLogger(BrokerFactory.class); 12 ThreadLocal<TaskCommand> local= new ThreadLocal<TaskCommand> (); 13 static ExecutorService executor = Executors.newCachedThreadPool(); 14 private BrokerFactory(){} 15 16 /** 17 * 支持的哪些命令 18 * @author Administrator 19 * 20 */ 21 public static enum CommandEnum{ 22 TEST1,TEST2,TEST3,NONE; 23 } 24 /** 25 * 单例模式 26 * @author Administrator 27 * 28 */ 29 static enum BrokerFactoryEnum{ 30 INSTANCE; 31 private BrokerFactory brokerFactory; 32 private BrokerFactoryEnum(){ 33 brokerFactory = new BrokerFactory(); 34 } 35 public BrokerFactory get(){ 36 return brokerFactory; 37 } 38 } 39 40 public static BrokerFactory buildBroker(){ 41 return BrokerFactoryEnum.INSTANCE.get(); 42 } 43 44 public static void shutDownTask(){ 45 try { 46 if(!executor.isTerminated()){ 47 executor.shutdown(); 48 } 49 } catch (Exception e) { 50 // TODO: handle exception 51 } 52 } 53 //创建命令 54 public BrokerFactory builderCommand(BrokerFactory.CommandEnum comd){ 55 TaskCommand b = new Broker(); 56 b.comd=comd; 57 local.set(b); 58 return this; 59 } 60 //设置参数 61 public BrokerFactory params(Object obj){ 62 TaskCommand comm= local.get(); 63 if(comm == null){ 64 throw new RuntimeException("先执行builderCommand方法"); 65 } 66 comm.params(obj); 67 local.set(comm); 68 return this; 69 } 70 71 /** 72 * 设置回调 73 * @param call 74 * @return 75 */ 76 public BrokerFactory call(TaskCommand.BackCall call){ 77 TaskCommand comm= local.get(); 78 if(comm == null){ 79 throw new RuntimeException("先执行builderCommand方法"); 80 } 81 comm.call=call; 82 local.set(comm); 83 return this; 84 } 85 86 //执行 87 public void execute(){ 88 TaskCommand comm= local.get(); 89 if(comm == null){ 90 throw new RuntimeException("先执行builderCommand方法"); 91 } 92 if(comm != null){ 93 executor.submit(new BrokerTask(comm)); 94 } 95 local.remove(); 96 } 97 98 public static abstract class TaskCommand { 99 private Object paras; 100 protected BrokerFactory.CommandEnum comd; 101 public BackCall call; 102 public final void execute(){ 103 Method[] declaredMethods = this.getClass().getDeclaredMethods(); 104 for(Method m : declaredMethods){ 105 try { 106 CommandBroker cb=m.getAnnotation(CommandBroker.class); 107 if(null != cb && cb.command().equals(this.comd)){ 108 if(null != m.getParameterTypes() && m.getParameterTypes().length>0){ 109 throw new RuntimeException("不支持传入参数,可以从父类中获取params"); 110 } 111 if (null == getParams()){ 112 logger.info("###BrokerFactory执行参数为空..."); 113 return ; 114 }
//这里可以加入统一的事件处理(执行前后通知或异常的处理,记录操作日志) 115 m.invoke(this); 117 if (null != call) 118 call.call(this); 119 return ; 120 } 121 } catch (Exception e) { 122 logger.error("###BrokerFactory执行任务异常:{}",e.fillInStackTrace()); 123 } 124 } 125 } 126 public final void params(Object paras){ 127 this.paras=paras; 128 } 129 public final Object getParams(){ 130 return this.paras; 131 } 132 //回调 133 public interface BackCall{ 134 void call(TaskCommand command); 135 } 138 } 139 140 private class BrokerTask implements Runnable{ 141 public TaskCommand command; 142 public BrokerTask(TaskCommand command){ 143 this.command=command; 144 } 145 146 @Override 147 public void run() { 148 command.execute(); 149 } 150 }161 }
3、新建Broker类
1 package com.test.util.Broker; 2 35 /** 36 * 数据推送指令集 37 * @author Administrator 38 * 39 */ 40 public class Broker extends TaskCommand{ 49 /** 50 * TEST1 51 */ 52 @CommandBroker(command=BrokerFactory.CommandEnum.TEST1) 53 public void test1Commander(){
Object paras = getParams();//获取参数 54 do something... 85 } 86 /** 87 * TEST2 88 */ 89 @CommandBroker(command=BrokerFactory.CommandEnum.TEST2) 90 public void test2Commander(){
Object paras = getParams(); 91 do something...108 } 109 110 /** 111 * TEST3 112 */ 113 @CommandBroker(command=BrokerFactory.CommandEnum.TEST3) 114 public void test3Commander(){
Object paras = getParams(); 115 do something...197 }212 }
用法:
1 BrokerFactory.buildBroker() 2 .builderCommand(BrokerFactory.CommandEnum.TEST1) 3 .params("1").execute(); 4 5 BrokerFactory.buildBroker() 6 .builderCommand(BrokerFactory.CommandEnum.TEST2) 7 .params("1").execute();