前幾天寫了一篇介紹枚舉功能強大的文章。有幾個朋友給我指正說,沒有案例單純描述不夠直觀。確實啊,在這里我就在寫一個案例篇,對上次的文章做補充說明。
此案例是一個游戲服務器的消息識別器的簡化。做過游戲開發都知道,客戶端和服務器之間的交互需要定義很多的消息類型,而且這個消息類型是需要不斷擴展的。消息識別器就是根據客戶端發送過來的消息編碼封裝成消息實體對象,以供業務邏輯層處理。這里就用這個簡化后的消息識別器展示一下枚舉的一個應用。(此處主要用作枚舉的一個應用實例演示,由於代碼做了簡化處理,設計上難免會有些不當之處,請見諒)
消息實體類的一個接口:
public interface IMsg { public void setMsgCode(int code); public void execute(); public void readData(IoBuffer bufer); public void writerData(IoBuffer bufer); }
消息實體類的一個抽象類:
public abstract class AbstractMsg implements IMsg{ protected int msgCode; public AbstractMsg(int msgCode){ this.msgCode = msgCode; } }
消息實體的一個實現類:
public class TestMsg extends AbstractMsg{ public TestMsg(int msgCode) { super(msgCode); } private int data1; private int data2; @Override public void setMsgCode(int code) { this.msgCode = code; } @Override public void execute() { //消息處理方法 } @Override public void readData(IoBuffer bufer) { this.data1 = bufer.getInt(); this.data2 = bufer.getInt(); } @Override public void writerData(IoBuffer bufer) { } }
為了模塊化管理,對枚舉類型抽出了一個接口,以后一個模塊的消息可以注冊到一個枚舉類上,而這些枚舉類都實現此接口
public interface IMsgCodeClass { public int getMsgCode(); public Class<? extends AbstractMsg> getMsgClass(); }
這是枚舉類,可以一個模塊一個枚舉類,該模塊下的消息都注冊到該枚舉類下
public enum MsgCodeClassConstants implements IMsgCodeClass{ test(1001,TestMsg.class)//在此就不多羅列一些了 ; private int msgCode; private Class<? extends AbstractMsg> msgClass; MsgCodeClassConstants(int msgCode,Class<? extends AbstractMsg> msgClass){ this.msgCode = msgCode; this.msgClass = msgClass; } @Override public int getMsgCode() { return msgCode; } @Override public Class<? extends AbstractMsg> getMsgClass() { return msgClass; } }
最后是消息識別器類:
public class MsgRecogniser { Map<Integer, Class<? extends AbstractMsg>> msges = new ConcurrentHashMap<Integer, Class<? extends AbstractMsg>>(); public void init(){ MsgCodeClassConstants[] contants = MsgCodeClassConstants.values(); for(int i=0;i<contants.length;i++){ msges.put(contants[i].getMsgCode(), contants[i].getMsgClass()); } } public IMsg getMsg(int msgCode){ IMsg msg = null; Class clazz = msges.get(msgCode); try { Constructor constructor = clazz.getConstructor(int.class); msg= (IMsg) constructor.newInstance(msgCode); } catch (Exception e) { e.printStackTrace(); } return msg; } }
消息識別器往往用在解碼器里,解碼器接收到數據后首先讀取消息編碼,然后根據編碼調用識別器獲取消息實體對象,調用消息實體對象的readData方法把客戶端數據獨到消息實體對象中。
以后要擴展消息時,只需要編寫消息實體類,然后注冊到枚舉類中就可以了。:)