首先引入我们的需求:
void contextLoads() {
int tag = new Random().nextInt(5);
if(tag == 0){
System.out.println("a");
}else if(tag == 1 ){
System.out.println("b");
}else if(tag == 2){
System.out.println("c");
} else if (tag == 3) {
System.out.println("d");
} else if (tag == 4) {
System.out.println("e");
}
}
这里利用随机数模拟用户传参,输出作为业务逻辑。
需求就是传入数字输出对应字母即可。这里使用了大量的if else。代码耦合度高,且不利于拓展和管理。
下面我将对其进行优化。
如果只是为了输出或者获取到对应值则可以直接使用枚举类。
public enum TagEnum {
a(0),b(1),c(2),d(3),e(4);
private int value;
TagEnum(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static TagEnum getName(int value) {
for (TagEnum tagEnum : values()) {
int value1 = tagEnum.getValue();
if(value1 == value){
return tagEnum;
}
}
return null;
}
}
通过getName方法遍历枚举找出对应数字的字母
void contextLoads() {
int tag = new Random().nextInt(5);
TagEnum name = TagEnum.getName(tag);
System.out.println(name);
}
这样原本的多行的if else就可以用一行代码搞定,并且如果需要拓展只需要增加枚举即可。
但是大部分情况业务逻辑不会单单只需要获取到对应值那么简单,有时会根据传入的参数不同执行不同的业务逻辑,那么就需要使用策略模式。
新建LetterHandler策略模式总接口
public interface LetterHandler {
void outLetter();
boolean checkLetter(Integer tag);
}
outLetter方法用于执行业务逻辑。
checkLetter方法用于区分实现类。
创建a,b,c,d,e的实现类
@Service
public class ALetterHandler implements LetterHandler {
@Override
public void outLetter() {
System.out.println("a");
}
@Override
public boolean checkLetter(Integer tag) {
return 0 == tag;
}
}
@Service
public class BLetterHandler implements LetterHandler {
@Override
public void outLetter() {
System.out.println("b");
}
@Override
public boolean checkLetter(Integer tag) {
return 1 == tag;
}
}
另外三个实现类类似。
@Autowired
private List<LetterHandler> letterHandlers;
@Test
void contextLoads() {
int tag = new Random().nextInt(5);
LetterHandler letterHandler = letterHandlers.stream().filter(item -> item.checkLetter(tag)).findFirst().orElse(null);
letterHandler.outLetter();
}
我们在调用时注入多个Service,通过filter找出需要的实现类,这样拓展时只需要新建一个实现类,继承策略方法总接口就可以了。
前面我们是通过总接口加上一个判断方法来区分需要的实现类的,还可以通过工厂设计的方式来区分:
其原理就是在springboot初始化bean的时候把LetterHandler和对应的数字存储到一个map,要用就通过key来取出LetterHandler
新建用于存储LetterHandler的工厂Factory
public class Factory {
private static final Map<Integer, LetterHandler> letterHandlerMap = new HashMap<>();
public static LetterHandler getLetterHandler(Integer key){
return letterHandlerMap.get(key);
}
public static void register(Integer key, LetterHandler letterHandler){
if(key == null || letterHandler == null) return;
letterHandlerMap.put(key, letterHandler);
}
}
getLetterHandler方法用于获取LetterHandler
register方法就是在初始化bean注册到letterHandlerMap里
在原来的基础上LetterHandler继承InitializingBean类
public interface LetterHandler extends InitializingBean
实现类实现afterPropertiesSet方法
ALetterHandler:
@Override
public void afterPropertiesSet() throws Exception {
Factory.register(0, this);
}
测试类:直接通过getLetterHandler获取实现类
void contextLoads() {
int tag = new Random().nextInt(5);
// LetterHandler letterHandler = letterHandlers.stream().filter(item -> item.checkLetter(tag)).findFirst().orElse(null);
// letterHandler.outLetter();
LetterHandler letterHandler = Factory.getLetterHandler(tag);
letterHandler.outLetter();
}
以上的业务逻辑outLetter是没有返回值的,现在我提升一下需求,tag为0,1,2时我需要输出对应字母,而tag为3,4时我要获取到对应字母。这样的需求根据现在的代码只能在总接口加一个返回值String类型的getLetter方法,但是这样所有的实现类都需要实现这个方法,那么每个实现类里都要有个空的方法,显然这么做是不合理的,这时候我们就需要使用模板设计的方法。
模板设计:
public abstract class LetterHandler implements InitializingBean {
public void outLetter(){
throw new UnsupportedOperationException();
}
public String getLetter(){
throw new UnsupportedOperationException();
}
public boolean checkLetter(Integer tag) {
return false;
}
}
将接口改造成抽象类,并写outLetter和getLetter中写一个抛出异常表示如果调用者没有该方法则会抛出异常。
ALetterHandler:
@Service
public class ALetterHandler extends LetterHandler {
@Override
public void outLetter() {
System.out.println("a");
}
@Override
public boolean checkLetter(Integer tag) {
return 0 == tag;
}
@Override
public void afterPropertiesSet() throws Exception {
Factory.register(0, this);
}
}
DLetterHandler:
@Service
public class DLetterHandler extends LetterHandler {
@Override
public String getLetter() {
return "d";
}
@Override
public boolean checkLetter(Integer tag) {
return 3 == tag;
}
@Override
public void afterPropertiesSet() throws Exception {
Factory.register(3, this);
}
}
测试类:
void contextLoads() {
for (int i = 0; i < 10; i++) {
int tag = new Random().nextInt(5);
LetterHandler letterHandler = Factory.getLetterHandler(tag);
try {
letterHandler.outLetter();
} catch (Exception e) {
String letter = letterHandler.getLetter();
System.out.println("获取" + letter);
}
}
}
这样我们就实现根据传入的参数去执行不同的方法是代码变得非常灵活