工作中運用到設計模式的開發場景

面試的時候,別人問起我工作這麼多年了,有沒有自己的一些沉澱和積累。其實高併發、分佈式都是很響亮的,然而我卻要講講用到的設計模式,也是一些細節。

  • 裝飾器(包裝器)模式:
public class ResponseMapWrapper {

	private static Logger logger = LoggerFactory.getLogger(ResponseMapWrapper.class);
	private static final String STATUS = "status";
	private static final String STATUS_TEXT = "statusText";
	private static final String DATA = "data";
	
	public static Map<String, Object> build(InfoCode infoCode, Object data) {

		Map<String, Object> map = new HashMap<>();
		
		map.put(STATUS, infoCode.getStatus());
		map.put(STATUS_TEXT, infoCode.getMsg());
		if (data != null) {
			map.put(DATA, data);
		}

		logger.info(JSON.toJSONString(map));
		return map;
	}

	public static Map<String, Object> build(ResponseCode responseCode) {

		Map<String, Object> map = new HashMap<>();
		
		map.put(STATUS, responseCode.getCode());
		map.put(STATUS_TEXT, responseCode.getReasonPhrase());

		logger.info(JSON.toJSONString(map));
		return map;
	}
}

InfoCode是enum類型,比如PARAMS_ERROR(40000, "參數錯誤"),這樣在Controller裏就能按照統一的格式返回,return ResponseMapWrapper.build(InfoCode.SUCCESS, vo);

  • 枚舉策略 + 簡單工廠模式:

最典型的就是微信公衆號開發中的event/msg了。從解析xml到對接具體的業務,event包括關注取消關注、掃碼、點擊菜單等,而msg包括了文本、圖片、語音等等,種類繁多,所以很適合枚舉策略。

接口:

public interface IEventStrategy {

  public String dealEvent(Element root);

}

實現:

public enum EventStrategy implements IEventStrategy {

  // 關注事件 || 掃描帶參數二維碼, 用戶未關注時,進行關注後的事件推送
  subscribe {
    @Override
    public String dealEvent(Element root) {
      return SubscribeStrategy.dealEvent(root);
    }
  },

  // 取消關注事件
  unsubscribe {
    @Override
    public String dealEvent(Element root) {
      return UnSubscribeStrategy.dealEvent(root);
    }
  },

  // 自定義菜單 —— 點擊菜單拉取消息時的事件
  CLICK {
    @Override
    public String dealEvent(Element root) {
      return ClickStrategy.dealEvent(root);
    }
  },

  // 自定義菜單 —— 點擊菜單跳轉鏈接時的事件
  VIEW {
    @Override
    public String dealEvent(Element root) {
      return ViewStrategy.dealEvent(root);
    }
  },

  // 模版消息發送任務完成後的事件
  TEMPLATESENDJOBFINISH {
    @Override
    public String dealEvent(Element root) {
      return TemplateSendStrategy.dealEvent(root);
    }
  }
}

具體的策略,以關注爲例:

public class SubscribeStrategy {
  private static final Logger logger = LoggerFactory.getLogger(SubscribeStrategy.class);

  /*
   * ToUserName 開發者微信號 FromUserName 發送方帳號(一個OpenID) CreateTime 消息創建時間 (整型) MsgType 消息類型,event Event
   * 事件類型,subscribe(訂閱)、unsubscribe(取消訂閱)
   */
  public static String dealEvent(Element root) {

    WxUserService wxUserService = (WxUserService) SpringContextUtils.getBeanById("wxUserService");

    NodeList toUserName = root.getElementsByTagName("ToUserName");
    NodeList fromUserName = root.getElementsByTagName("FromUserName");
    NodeList createTime = root.getElementsByTagName("CreateTime");

    String developerId = toUserName.item(0).getTextContent();
    String openId = fromUserName.item(0).getTextContent();
    String _createTime = createTime.item(0).getTextContent();
    NodeList eventKey = root.getElementsByTagName("EventKey");
    String _eventKey = "";
    if (eventKey != null) {
      _eventKey = eventKey.item(0).getTextContent();
    }

    logger.info("SubscribeStrategy toUserName: {}; fromUserName: {}; createTime: {}; eventKey: {}",
        developerId, openId, _createTime, _eventKey);

    UserInfo userInfo = wxUserService.getUserInfo(openId);

    // 以unionId爲Key
    String unionid = userInfo.getUnionid();
    RedisUtils redisUtils = (RedisUtils) SpringContextUtils.getBeanByClass(RedisUtils.class);

    if (unionid == null) {
      logger.warn("weclome get unionid failed,  userOpenId : {}", openId);
    } else {
      // 存儲用戶信息
      redisUtils.setStrNX(openId, unionid);
      userInfo.setSubscribe(1);
      redisUtils.setPOJO(unionid, userInfo);
    }

    // 以下與具體業務對接
    @TODO
}

對外調用是通過簡單工廠提供的方法:

public class EventStrategyFactory {

  public static IEventStrategy getDealer(String event) {

    // 按事件發生概率由高到低排序
    switch (event) {

    // 自定義菜單 —— 點擊菜單拉取消息時的事件
      case "CLICK":
        return EventStrategy.CLICK;

        // 自定義菜單 —— 點擊菜單跳轉鏈接時的事件
      case "VIEW":
        return EventStrategy.VIEW;

        // 關注事件 || 掃描帶參數二維碼, 用戶未關注時,進行關注後的事件推送
      case "subscribe":
        return EventStrategy.subscribe;

        // 模版消息發送任務完成後的事件
      case "TEMPLATESENDJOBFINISH":
        return EventStrategy.TEMPLATESENDJOBFINISH;

        // 取消關注事件
      case "unsubscribe":
        return EventStrategy.unsubscribe;

      default:
        return null;
    }
  }
}

入口,xml節點是event時,不關心具體的event名稱,EventStrategyFactory.getDealer(_event)從工廠拿到策略,然後啓用該策略。

if ("event".equals(_msgType)) {
        NodeList event = root.getElementsByTagName("Event");
        String _event = event.item(0).getTextContent();
        IEventStrategy eventStrategy = EventStrategyFactory.getDealer(_event);
        if(eventStrategy != null){
          replyMsg = eventStrategy.dealEvent(root);
        }
        
      }
  • 享元模式:

複用map,不要每次都new一個map,這樣創建的開銷很大,而且還會垃圾回收。具體等我找一下代碼。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章