項目中的if else太多了,該怎麼重構?

介紹

最近跟著公司的大佬開發了一款IM系統,類似QQ和微信哈,就是聊天軟件。我們有一部分業務邏輯是這樣的

if (msgType = "文本") {

// dosomething

} else if(msgType = "圖片") {

// doshomething

} else if(msgType = "視頻") {

// doshomething

} else {

// doshomething

}

就是根據消息的不同類型有不同的處理策略,每種消息的處理策略代碼都很長,如果都放在這種if else代碼快中,代碼很難維護也很醜,所以我們一開始就用了策略模式來處理這種情況。

策略模式還挺簡單的,就是定義一個接口,然後有多個實現類,每種實現類封裝了一種行為。然後根據條件的不同選擇不同的實現類。

實現過程

消息對象,當然真實的對象沒有這麼簡單,省略了很多屬性

@Data

@AllArgsConstructor

public class MessageInfo {

// 消息類型

private Integer type;

// 消息內容

private String content;

}

定義一個消息處理接口

public interface MessageService {

void handleMessage(MessageInfo messageInfo);

}

有2個消息處理接口,分別處理不同的消息

處理文本消息

@Service

@MsgTypeHandler(value = MSG_TYPE.TEXT)

public class TextMessageService implements MessageService {

@Override

public void handleMessage(MessageInfo messageInfo) {

System.out.println("處理文本消息 " + messageInfo.getContent());

}

}

處理圖片消息

@Service

@MsgTypeHandler(value = MSG_TYPE.IMAGE)

public class ImageMessageService implements MessageService {

@Override

public void handleMessage(MessageInfo messageInfo) {

System.out.println("處理圖片消息 " + messageInfo.getContent());

}

}

文章寫到這,可能大多數人可能會想到要需要如下一個Map, Map,這樣直接根據消息類型就能拿到消息處理對象,調用消息處理對象的方法即可。我們就是這樣做的,但是我們不想手動維護這個Map對象,因為每次增加新的消息處理類,Map的初始化過程就得修改

我們使用了註解+ApplicationListener來保存這種映射關係,來看看怎麼做的把

定義一個消息類型的枚舉類

public enum MSG_TYPE {

TEXT(1, "文本"),

IMAGE(2, "圖片"),

VIDEO(3, "視頻");

public final int code;

public final String name;

MSG_TYPE(int code, String name) {

this.code = code;

this.name = name;

}

}

定義一個註解

@Documented

@Inherited

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

public @interface MsgTypeHandler {

MSG_TYPE value();

}

不知道你注意到了沒,前面的代碼中,每種消息處理類上面都有一個@MsgTypeHandler註解,表明了這個處理類

處理哪種類型的消息

@Service

@MsgTypeHandler(value = MSG_TYPE.TEXT)

public class TextMessageService implements MessageService {

@Override

public void handleMessage(MessageInfo messageInfo) {

System.out.println("處理文本消息 " + messageInfo.getContent());

}

}

用一個context對象保存了消息類型->消息處理對象的映射關係

@Component

public class MessageServiceContext {

private final Map<integer> handlerMap = new HashMap<>();/<integer>

public MessageService getMessageService(Integer type) {

return handlerMap.get(type);

}

public void putMessageService(Integer code, MessageService messageService) {

handlerMap.put(code, messageService);

}

}

最精彩的部分到了

@Component

public class MessageServiceListener implements ApplicationListener<contextrefreshedevent> {/<contextrefreshedevent>

@Override

public void onApplicationEvent(ContextRefreshedEvent event) {

Map<string> beans = event.getApplicationContext().getBeansWithAnnotation(MsgTypeHandler.class);/<string>

MessageServiceContext messageServiceContext = event.getApplicationContext().getBean(MessageServiceContext.class);

beans.forEach((name, bean) -> {

MsgTypeHandler typeHandler = bean.getClass().getAnnotation(MsgTypeHandler.class);

messageServiceContext.putMessageService(typeHandler.value().code, (MessageService) bean);

});

}

}

在spring的啟動過程中,通過解析註解,將消息類型->消息處理對象的映射關係保存到MessageServiceContext對象中

@Autowired

MessageServiceContext messageServiceContext;

@Test

public void contextLoads() {

// 構建一個文本消息

MessageInfo messageInfo = new MessageInfo(MSG_TYPE.TEXT.code, "消息內容");

MessageService messageService = messageServiceContext.getMessageService(messageInfo.getType());

// 處理文本消息 消息內容

// 可以看到文本消息被文本處理類所處理

messageService.handleMessage(messageInfo);

}

測試類正常工作,通過策略模式避免了寫大量的if else代碼,也更容易維護


分享到:


相關文章: