内容简介:APT实用案例一:状态模式之就算违背开闭原则又何妨?
前言
状态模式主要是从业务逻辑中将条件判断逻辑抽离出来,再对这些判断逻辑进行封装、管理。UML如下:
事实上,也就是将条件判断逻辑移植到了Context中而已,如果不做特殊处理,Context中的if else亦或是switch case都要写一堆, 每当State的实现增加的时候,条件判断就要加一个分支 ,这样的设计,有违开闭原则。
前文中,采用了反射机制去解决了这一问题,但是众所周知, 反射生成实例的性能开销远远比new出来的要大得多 。本文将采用APT的方式去处理这一问题。
思路及实现
状态模式中存在的问题就是条件判断无法自动化,也即是if else或者switch case这样的重复代码无法自动生成,这时候我们的APT无异于雪中送炭。
此处还是用之前的返回码案例:
预想下所要达到的目的:在状态实现类中加上注解@RCode(“xxxx”)这样的标识,就能自动在RCContext中生成相应的判断分支。
//想象中的实现
@RCode("0000")
public class ReturnCode0000 implements ReturnCode {
@Override
public void doOnReturn(Map m) {
System.out.println("return code = 0000");
}
}
public final class RCContext {
private ReturnCode rc;
public void handleReturn(Map m) {
String return_code = m.get("return_code").toString();
switch(return_code) {
case "0000":
rc = new ReturnCode0000();
rc.doOnReturn(m);
break;
}
}
}
OK,有目标我们就开始动手了。(APT环境搭建不在本文赘述,可点击这里查看)
首先,我们先新建返回码基类ReturnCode
public interface ReturnCode {
void doOnReturn(Map m);
}
其次,我们先新建注解RCode
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface RCode {
String value();
}
RCContext上下文类通过注解处理类自动生成
@AutoService(Processor.class)
@SupportedAnnotationTypes({
"com.aop.anno.RCode"
})
public class RCContextProcessor extends AbstractProcessor{
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
//生成RCContext类及成员变量ReturnCode
TypeSpec.Builder tb = TypeSpec.classBuilder("RCContext")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
//bestGuess方法是在apt module内无法获取到某个Class,但是在app module里能获取到时采用
.addField(ClassName.bestGuess("com.drdzsd.apttest.code.ReturnCode"), "rc", Modifier.PRIVATE);
//生成handleReturn
MethodSpec.Builder mb = MethodSpec.methodBuilder("handleReturn")
.addParameter(ClassName.get(Map.class), "m")
.addModifiers(Modifier.PUBLIC);
//handleReturn方法的代码块
CodeBlock.Builder cb = CodeBlock.builder()
.addStatement("String return_code = m.get(\"return_code\").toString()")
.beginControlFlow("switch(return_code)");
for(TypeElement element : ElementFilter.typesIn(roundEnv.getElementsAnnotatedWith(RCode.class))){
cb.add("case \"$L\":\n\trc = new $T();\n", element.getAnnotation(RCode.class).value(), element);
cb.addStatement("\trc.doOnReturn(m)");
cb.addStatement("break");
}
cb.endControlFlow();
mb.addCode(cb.build());
tb.addMethod(mb.build());
JavaFile jf = JavaFile.builder("com.example.apt", tb.build()).build();
try {
jf.writeTo(processingEnv.getFiler());
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
}
最后,我们创建返回码实现类,并添加@RCode(xxxx)注解,Rebuild一下,便能自动生成RCContext类了,判断条件逻辑再也不需要我们手动去修改RCContext类了!
public final class RCContext {
private ReturnCode rc;
public void handleReturn(Map m) {
String return_code = m.get("return_code").toString();
switch(return_code) {
case "0000":
rc = new ReturnCode0000();
rc.doOnReturn(m);
break;
case "0001":
rc = new ReturnCode0001();
rc.doOnReturn(m);
break;
case "0140":
rc = new ReturnCode0140();
rc.doOnReturn(m);
break;
}
}
}
总结
从代码上来看,RCContext依然是有违开闭原则的,但是违背开闭原则所产生的弊端,都让APT去自动解决了。
——违背开闭原则又何妨?我有APT来帮忙!
以上所述就是小编给大家介绍的《APT实用案例一:状态模式之就算违背开闭原则又何妨?》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Mechanics of Web Handling
David R. Roisum
This unique book covers many aspects of web handling for manufacturing, converting, and printing. The book is applicable to any web including paper, film, foil, nonwovens, and textiles. The Mech......一起来看看 《The Mechanics of Web Handling》 这本书的介绍吧!