問題
增加對象類型需要增加對應工廠類。同時要將相應的工廠類設置到需要生成對象的模塊中。強類型綁定增加過多的類似代碼。
目標
使用泛型抽象要生成的對象,使用抽象工廠,動態化設定工廠類型。
實現
- 默認類型
// 一個簡單的消息對象,內部類設計並不友好
public class DefaultPacket {
private static DefaultPacket dp = new DefaultPacket();
private int cmd;
private Content content;
private String seq;
private DefaultPacket() {
this.seq = UUID.randomUUID().toString();
}
public DefaultPacket(int cmd, Content content) {
this();
this.cmd = cmd;
this.content = content;
}
public int getCmd() {
return cmd;
}
public void setCmd(int cmd) {
this.cmd = cmd;
}
public Content getContent() {
return content;
}
public void setContent(Content content) {
this.content = content;
}
public String getSeq() {
return seq;
}
public void setSeq(String seq) {
this.seq = seq;
}
@Override
public String toString() {
return this.getClass().getName() + " [cmd=" + cmd + ", content=" + content + ", seq=" + seq + "]";
}
public static Content newContent(String msg, int status, int result, String desc) {
return dp.new Content(msg, status, result, desc);
}
public class Content {
private String msg;
private int status;
private int result;
private String desc;
public Content(String msg, int status, int result, String desc) {
super();
this.msg = msg;
this.status = status;
this.result = result;
this.desc = desc;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public int getResult() {
return result;
}
public void setResult(int result) {
this.result = result;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Override
public String toString() {
return "Content [msg=" + msg + ", status=" + status + ", result=" + result + ", desc=" + desc + "]";
}
}
}
- 帶着點抽風的工廠類
public abstract class PacketFactory {
private static Map<String, PacketFactory> factorys;
// 私有構造方法,不允許直接生成對象
private PacketFactory() {
}
/**
* 構造工廠實體
* @param clazz 用於生成目標的對象類型
* @return Factory build packet with clazz type
*/
public static PacketFactory getFactory(Class<? extends DefaultPacket> clazz) {
if (factorys == null) {
factorys = new HashMap<>();
}
String name = clazz.getName();
PacketFactory factory;
// 力所能及的加個緩存
if ((factory = factorys.get(name)) == null) {
factory = new PacketFactory() {
@SuppressWarnings("unchecked")
@Override
public <T extends DefaultPacket> T getPacket(int cmd, Content content) {
DefaultPacket packet = null;
Constructor<? extends DefaultPacket> constructor = null;
try {
constructor = clazz.getConstructor(int.class, Content.class);
packet = constructor.newInstance(cmd, content);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(
String.format("%s構造方法不符合約定參數列表(int cmd,Content content)", clazz.getName()));
}
return (T) packet;
}
};
factorys.put(name, factory);
}
return factory;
}
/**
* 直接獲得生成默認類型的工廠
* @return PacketFactory with defaultPacket
*/
public static PacketFactory getFactory() {
return getFactory(DefaultPacket.class);
}
/**
* 獲得消息對象
* @param cmd
* @param content
* @return
*/
public abstract <T extends DefaultPacket> T getPacket(int cmd, Content content);
}
參考
mybatis中泛型在內部進行強制類型轉換。
以抽象類直接獲得對象實例。