あなたが想像していたよりも強力な列挙タイプ---ケース編

3758 ワード

先日、列挙機能の強い文章を紹介しました.何人かの友达が私に指摘してくれたが、単純な説明が直感的ではないケースはないと言った.確かに、ここではケース編を書いて、前回の文章について補足説明します.
このケースは、ゲームサーバのメッセージ識別器の簡略化です.ゲーム開発をしたことがあることはよく知られていますが、クライアントとサーバの間のインタラクションには多くのメッセージタイプを定義する必要があり、このメッセージタイプは絶えず拡張する必要があります.メッセージ識別器は、クライアントから送信されたメッセージ符号化に基づいて、ビジネスロジック層が処理するためにメッセージエンティティオブジェクトにカプセル化される.ここでは,この簡略化されたメッセージ識別器を用いて列挙されたアプリケーションを示す.(ここでは主に列挙の応用例のプレゼンテーションとして用いられていますが、コードが簡略化されているため、設計上の不適切な点が避けられませんので、ご了承ください)
メッセージエンティティークラスのインタフェース:
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法により、クライアントデータをメッセージエンティティオブジェクトにユニークにする.
後でメッセージを拡張する場合は、メッセージエンティティクラスを作成し、列挙クラスに登録するだけです.:)