不管在什么软件公司,不管做什么软件业务,当产品不断迭代业务不断变更后,咱们的程序代码也会越来越臃肿越来越冗余。
在一个维护了几年的系统中,有的时候我们会发现一个方法几百行,甚至上千行的都有,方法里面嵌套了数不清的if else,不可思议,无法理解。看到这样的方法,特别是前人都没有留啥注释,真的很蛋疼。
所以在这种情况下,咱们就想到了用设计模式,将一个方法拆分成n个方法,每个方法负责不同的功能模块,然后将所有的方法组合在一起形成一个主要的大功能模块。这也是封装思想的理想模式。
废话不多说咱们先看一个例子:
public Integer saveOrder(OrderVar var){
//校验参数
if(var == null){
throw new RuntimeException("*******");
}
if(var.getMoney() == null || var.getMoney() <= 0){
throw new RuntimeException("*******");
}
if(var.getUserId() == null){
throw new RuntimeException();
}
……………… //此处省略300行代码
//保存订单
Order order = new Order();
order.setOrderId(orderId)
.setMoney(money)
.setObject(obj)
.setStatus(4)
.setOrderType(5)
.setCreateAt(new Date);
orderService.save(order);
OrderExt orderExt = new OrderExt();
orderExt.setOrderId(orderId)
.setUserId(userId)
.setSellBl(bll)
.setStatus(4)
.setType(3)
.setlocal(local)
.setbusiness(business)
.setPerll(perll)
.setCreateAt(new Date);
orderExtService.save(orderExt);
}
随便写了一点代码,咱们就姑且把这个方法当成一个无比简化版下单的方法吧,这里简略写下。
一般情况下这种类型的方法拆分起来很简单,只需要将这三个功能拆分成三个方法,然后在一个方法中调用即可。但是实际上相关的业务却比这复杂的多,下单的业务涉及到用户,账户,各种卷,商家,物流,银行,日志,第三方等等等等,如果将一个下单的全部代码放到一个方法中,估计得要有几万行,即使是spring这种service分类分功能的,也会有各种逻辑业务嵌套,无法避免的一个方法也会出现成百上千行,而且spring的service方法之间调用需要不断的传递参数,偶尔一个参数没有传递,或者没有返回就会导致业务执行不下去,然后咱们有要改方法,改了这个方法,其他n个调用的方法又要改,心都碎了……
那么怎么办呢,很自然的咱们想到了设计模式,工厂模式,命令模式,责任链模式等等等等。
一个方法很长,那么我们是不是可以将这个方法封装成一个类,这个类完全就用来实现这个业务,不做其他任何事情。
就拿上面的下单为例:
咱们调用的时候就可以直接 new Create
这样咱们的下单逻辑就完全集中到CreateOrder中了,而且CreateOrder因为是new出来的新的对象,所以这个类中咱们可以随便定义全局变量,这样的话咱们的方法之间就不用为参数犯愁了,反正参数都在CreateOrder对象中哈哈,简直完美。
不过凡是都不会这么顺利,问题来了!
哈哈,这个对象是咱们自己new出来的,又不是spring管理的,当然就不能注入对象喽,可是不能注入对象,咱们怎么办呢,这不是坑吗!想了一下,注入不了对象,咱们可以在spring容器中查啊!
不废话继续
嗯,这样就可以了,非常nice啊,不过哥是个追求完美的人,咱们不能每做一个业务操作,都在spring中获取service或者dao吧,这太尴尬了,完全不能接受嘛!
那么怎么办呢?
对了!spring是肯定不会给我们注入的,但是难道咱们自己不能注入吗,脑袋浆糊啦
接下来才是见证奇迹的时刻哈哈
@Slf4j
public abstract class AbstractCmd<T>{
/**
* 获取当前命令对象的所有带 @Autowired注解的属性,然后从spring上下文中获取到注入进去
*/
public AbstractCmd(Object params){
String cmdName = this.getClass().getSimpleName();
log.info("开始执行命令:"+cmdName);
if(log.isDebugEnabled()){
log.debug("执行命令["+cmdName+"]参数:"+JsonHelper.toJson(params));
}
List<Field> fields = getFields(getClass(),new ArrayList<>());
if(!ObjectUtils.isEmpty(fields)){
for(Field field : fields){
//spring bean
Autowired autowired = field.getAnnotation(Autowired.class);
if(autowired != null){
Class<?> bean = field.getType();
Object springBean = SpringApplicationContext.getBean(bean);
Assert.isTrue(!ObjectUtils.isEmpty(springBean),"bean: "+bean.getName()+" not found in spring application!");
try {
field.setAccessible(true);
field.set(this,springBean);
} catch (IllegalAccessException e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage(),e);
}
}
//dubbo
Reference reference = field.getAnnotation(Reference.class);
if(reference != null){
Class<?> type = field.getType();
AnnotationInjectedBeanPostProcessor postProcessor = SpringContextUtils.getBean(AnnotationInjectedBeanPostProcessor.class);
List<Method> methods = getMethods(postProcessor.getClass(),new ArrayList<>());
for(Method method : methods){
if(method.getName().equals("doGetInjectedBean")){
method.setAccessible(true);
try {
DubboElement element = new DubboElement(null,null);
Object bean = method.invoke(postProcessor,reference,null,null,type,element);
field.setAccessible(true);
field.set(this,bean);
} catch (Exception e) {
e.printStackTrace();
}
break;
}
}
}
}
}
}
private List<Field> getFields(Class copy, List<Field> fields){
fields.addAll(Arrays.asList(copy.getDeclaredFields()));
if(copy.getSuperclass() != Object.class){
Class superCopy = copy.getSuperclass();
getFields(superCopy,fields);
return fields;
}else{
return fields;
}
}
private List<Method> getMethods(Class bean,List<Method> methods){
methods.addAll(Arrays.asList(bean.getDeclaredMethods()));
if(bean.getSuperclass() != Object.class){
Class superCopy = bean.getSuperclass();
getMethods(superCopy,methods);
return methods;
}else{
return methods;
}
}
protected class DubboElement extends InjectionMetadata.InjectedElement{
protected DubboElement(Member member, PropertyDescriptor pd) {
super(member, pd);
}
}
public abstract T execute();
}
咱们先做一个抽象的注入父类,这个父类没啥特殊的,就是通过反射来获取spring中的bean,然后自己手动塞到被Autowired注解注释的属性中,简直lou的不要不要的,然后在创建一个CreateOrder子类,来继承这个父类,额就是这么简单
public class CreateOrder extends AbstractCmd<Integer>{
private OrderVar var;
@Autowired
private OrderService orderService;
public CreateOrder(OrderVar var){
super(var);
this.var = var;
}
@Override
public Integer execute() {
orderService.save();
return 1;
}
}
哈哈,结束啦