我所实现的功能是这样的:会有很多个精灵,这些精灵都需要相应的条件判断才能创建对应的精灵,如果直接用工厂模式创建的话,随着精灵数量的增多,会让工厂方法难以招架,于是我将其改为mvc模式来实现:
angelReflectConfig.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!--
isAllUsed:是否在web解锁和踩点解锁时都必须判断精灵
isOnlyWebUsed:是否只在web端解锁升级时使用该精灵
isOnlyCheckUsed:是否只在踩点解锁时使用该精灵
isLegal:使用逻辑判断是否创建该精灵
上面四中情况只需要写一种就可以了,如果写多个,会抛出异常终止服务器启动,如果设置的属性为false,则默认进入isLegal模式
id:精灵编号,必须唯一
-->
<angels>
<angel isAllUsed="true" id="18">
com.lifeix.angel.strategy.HappyBirthdayStrategy
</angel>
<angel isAllUsed="true" id="1">
com.lifeix.angel.strategy.NewbieStrategy
</angel>
<angel isOnlyCheckUsed="true" id="3">
com.lifeix.angel.strategy.AdventurerStrategy
</angel>
<angel isOnlyCheckUsed="true" id="9">
com.lifeix.angel.strategy.CasanovaStrategy
</angel>
<angel isOnlyCheckUsed="true" id="12">
com.lifeix.angel.strategy.OtakuStrategy
</angel>
<angel isOnlyCheckUsed="true" id="26">
com.lifeix.angel.strategy.SuperCaptainStrategy
</angel>
<angel isLegal="true" id="71">
com.lifeix.angel.strategy.AlmightyStrategy
</angel>
<angel isLegal="true" id="74">
com.lifeix.angel.strategy.BigVegasStrategy
</angel>
<angel isLegal="true" id="27">
com.lifeix.angel.strategy.BirdieKingStrategy
</angel>
<angel isLegal="true" id="85">
com.lifeix.angel.strategy.CarFanStrategy
</angel>
<angel isLegal="true" id="76">
com.lifeix.angel.strategy.DrunkardStrategy
</angel>
<angel isLegal="true" id="73">
com.lifeix.angel.strategy.EnvironmentalistStrategy
</angel>
<angel isLegal="true" id="29">
com.lifeix.angel.strategy.FashionInsiderStrategy
</angel>
<angel isLegal="true" id="24">
com.lifeix.angel.strategy.FrequentFlierStrategy
</angel>
<angel isLegal="true" id="82">
com.lifeix.angel.strategy.GameJunkieStrategy
</angel>
<angel isLegal="true" id="83">
com.lifeix.angel.strategy.GoldenBachelorStrategy
</angel>
<angel isLegal="true" id="31">
com.lifeix.angel.strategy.GourmetStrategy
</angel>
<angel isLegal="true" id="79">
com.lifeix.angel.strategy.KnowNothingStrategy
</angel>
<angel isLegal="true" id="19">
com.lifeix.angel.strategy.MidnightAngelStrategy
</angel>
<angel isLegal="true" id="84">
com.lifeix.angel.strategy.MostFeminineStrategy
</angel>
<angel isLegal="true" id="81">
com.lifeix.angel.strategy.MovieFanStrategy
</angel>
<angel isLegal="true" id="87">
com.lifeix.angel.strategy.MusicFanStrategy
</angel>
<angel isLegal="true" id="80">
com.lifeix.angel.strategy.OneNightStandStrategy
</angel>
<angel isLegal="true" id="86">
com.lifeix.angel.strategy.PhotographerStrategy
</angel>
<angel isLegal="true" id="88">
com.lifeix.angel.strategy.PinStrategy
</angel>
<angel isLegal="true" id="77">
com.lifeix.angel.strategy.RoadBullyStrategy
</angel>
<angel isLegal="true" id="17">
com.lifeix.angel.strategy.SexyFigureStrategy
</angel>
<angel isLegal="true" id="75">
com.lifeix.angel.strategy.ShopaholicStrategy
</angel>
<angel isLegal="true" id="16">
com.lifeix.angel.strategy.SingingStarStrategy
</angel>
<angel isLegal="true" id="72">
com.lifeix.angel.strategy.SingleNobleStrategy
</angel>
<angel isLegal="true" id="78">
com.lifeix.angel.strategy.SportsFanStrategy
</angel>
</angels>
CacheAngelConfigFromFactory.java文件
package com.lifeix.angel.angelreflect;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.l99.dto.angel.Angel;
import com.lifeix.angel.bean.CheckinCondition;
import com.lifeix.angel.service.UserAngelService;
import com.lifeix.angel.strategy.BasicStrategy;
/**
* @DESCRIPTION:
**/
public class CacheAngelConfigFromFactory {
private static final Logger log = LoggerFactory.getLogger(CacheAngelConfigFromFactory.class);
public static final int ALLUSEDCACHE = 0;
public static final int ONLYWEBUSEDCAHCE=1;
public static final int ONLYCHECKUSEDCACHE=2;
public static final int LEGALCACHE=3;
//是否在web解锁和踩点解锁时都必须判断精灵
public static Map<Integer, String> allUsedCache = new HashMap<Integer, String>();
//是否只在web端解锁升级时使用该精灵
public static Map<Integer, String> onlyWebUsedCache = new HashMap<Integer, String>();
//是否只在踩点解锁时使用该精灵
public static Map<Integer, String> onlyCheckUsedCache = new HashMap<Integer, String> ();
//使用逻辑判断是否创建该精灵
public static Map<Integer, String> legalCache = new HashMap<Integer, String> ();
public static void initConfig() {
String filePath = System.getProperty("angelConfig");
if(null == filePath || "".equals(filePath)) {
log.info("配置文件的angelConfig元素不能为空,服务器被终止启动......................");
System.exit(0);
} else {
URL url = CacheAngelConfigFromFactory.class.getResource(filePath);
if(null == url || "".equals(url)) {
log.info("找不到配置文件【"+filePath+"】,服务器被终止启动......................");
System.exit(0);
} else {
File file = new File(url.getFile());
log.info("config path:" + file.getAbsolutePath());
parseFile(file);
}
}
}
private static void parseFile(File file) {
Document doc = null;
try {
doc = new SAXReader().read(file);
Element rootElement = doc.getRootElement();
Iterator it = rootElement.elementIterator("angel");
while(it.hasNext()) {
Element ele = (Element) it.next();
List<Attribute> attrs = ele.attributes();
if(attrs.size() > 2) {
log.info("元素【" + ele.getName() + "】的属性只能为两个");
System.exit(0);
break;
} else {
String text = ele.getTextTrim();
boolean flag = false;
int id = Integer.parseInt(ele.attribute("id").getText().trim());
if(allUsedCache.containsKey(id) || onlyWebUsedCache.containsKey(id) ||
onlyCheckUsedCache.containsKey(id) || legalCache.containsKey(id)) {
log.info("已经存在ID值【"+id+"】,服务器被终止启动......................");
System.exit(0);
}
for(Attribute attr : attrs) {
String name = attr.getName();
String value = attr.getValue();
if("isAllUsed".equals(name) && Boolean.parseBoolean(value)) {
allUsedCache.put(id, text);
flag = !flag;
} else if("isOnlyWebUsed".equals(name) && Boolean.parseBoolean(value)) {
onlyWebUsedCache.put(id, text);
flag = !flag;
} else if("isOnlyCheckUsed".equals(name) && Boolean.parseBoolean(value)) {
onlyCheckUsedCache.put(id, text);
flag = !flag;
} else if(!flag || "isLegal".equals(name)) {
legalCache.put(id, text);
}
}
}
}
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* @description:创建精灵
* @return:void
* @param condition
* @param data
* @param flag
*/
public static void putAngel(CheckinCondition condition, Map<Long, BasicStrategy> data, int flag) {
if(flag == ALLUSEDCACHE) {
generateAngelEntity(condition, data, allUsedCache);
} else if(flag == ONLYWEBUSEDCAHCE) {
generateAngelEntity(condition, data, onlyWebUsedCache);
} else if(flag == ONLYCHECKUSEDCACHE) {
generateAngelEntity(condition, data, onlyCheckUsedCache);
} else if(flag == LEGALCACHE) {
generateAngelEntity(condition, data);
} else {
throw new IllegalArgumentException("invalid parameter.............");
}
}
private static void generateAngelEntity(CheckinCondition condition, Map<Long, BasicStrategy> data) {
if(legalCache.size() > 0) {
Angel angel = UserAngelService.getUserAngelByAngelId(condition.getAccountId(), condition.getAngelId());
String packagePath = legalCache.get(Integer.parseInt("" + condition.getAngelId()));
data.put(condition.getAngelId(),reflectAngelEntity(packagePath, condition, angel));
}
}
private static void generateAngelEntity(CheckinCondition condition, Map<Long, BasicStrategy> data, Map<Integer, String> cache) {
if(cache.size() > 0) {
for(Entry<Integer, String> entry : cache.entrySet()) {
CheckinCondition cc = getCondition(condition);
cc.setAngelId(entry.getKey());
Angel angel = UserAngelService.getUserAngelByAngelId(cc.getAccountId(), cc.getAngelId());
data.put(cc.getAngelId(),reflectAngelEntity(entry.getValue(), cc, angel));
}
}
}
/**
* @description: 反射精灵类
* @return:BasicStrategy
* @param packagePath
* @return
* @throws ClassNotFoundException
* @throws InvocationTargetException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws IllegalArgumentException
*/
private static BasicStrategy reflectAngelEntity (String packagePath, CheckinCondition cc, Angel angel) {
Class clazz = null;
try {
clazz = Class.forName(packagePath);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(null == clazz) {
throw new NullPointerException("包路径载入异常......" + packagePath);
}
Constructor<?>[] cons = clazz.getConstructors();
if(cons.length > 0) {
for(Constructor con : cons) {
if(con.getParameterTypes().length == 2) {
BasicStrategy bs = null;
try {
bs = (BasicStrategy) con.newInstance(cc, angel);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("invalid parameter.............");
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return bs;
}
}
}
throw new NullPointerException("生成精灵实体为空......" + angel.getMedalId());
}
/**
* @description: 复制一份,防止多线程共享同一个对象,造成数据混乱
* @author:fuqiangj
* @return:CheckinCondition
* @param condition
* @return
*/
public static CheckinCondition getCondition(CheckinCondition condition) {
CheckinCondition cc = new CheckinCondition();
cc.setAccountId(condition.getAccountId());
cc.setAngelId(condition.getAngelId());
cc.setBirthday(condition.getBirthday());
cc.setCatId(condition.getCatId());
cc.setCheckIn(condition.isCheckIn());
cc.setCreate(condition.isCreate());
cc.setGender(condition.getGender());
cc.setIpAddress(condition.getIpAddress());
cc.setLocalId(condition.getLocalId());
cc.setAddVillage(condition.isAddVillage());
return cc;
}
}
AngelStrategyFactory.java类
package com.lifeix.angel.factory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.perf4j.StopWatch;
import org.perf4j.slf4j.Slf4JStopWatch;
import com.l99.dto.angel.Angel;
import com.lifeix.angel.angelreflect.CacheAngelConfigFromFactory;
import com.lifeix.angel.bean.AngelType;
import com.lifeix.angel.bean.CheckinCondition;
import com.lifeix.angel.service.UserAngelService;
import com.lifeix.angel.service.share.AngelServiceShare;
public class AngelStrategyFactory {
static final StopWatch STOP_WATCH = new Slf4JStopWatch();
/**
* 生成用户需要解锁或升级的精灵策略
* @param accountId
* @return
*/
public static List<BasicStrategy> generateStrategies(CheckinCondition condition){
//临时存放数据,防止重复添加精灵
Map<Long, BasicStrategy> data = new HashMap<Long, BasicStrategy>();
if (condition==null) {
throw new IllegalArgumentException("没有解锁条件,无法生成解锁策略...");
}
CacheAngelConfigFromFactory.putAngel(condition, data, CacheAngelConfigFromFactory.ALLUSEDCACHE);
if (!condition.isCheckIn()) {//web 端精灵策略
generateWebStrategies(condition, data);
}else {//踩点精灵策略
generateCheckInStrategies(condition,data);
}
List<BasicStrategy> strategies = new ArrayList<BasicStrategy>();
if(data.size() > 0) {
for(BasicStrategy entry : data.values()) {
strategies.add(entry);
}
data.clear();
}
return strategies;
}
/**
* 生成web端精灵策略
* @param accountId
* @param condition
* @param strategies
*/
private static void generateWebStrategies(CheckinCondition condition, Map<Long, BasicStrategy> data){
CacheAngelConfigFromFactory.putAngel(condition, data, CacheAngelConfigFromFactory.ONLYWEBUSEDCAHCE);
parseAngel(condition, data);
}
/**
* 生成踩点精灵策略
*
* @param condition
* @param strategies
*/
private static void generateCheckInStrategies(CheckinCondition condition, Map<Long, BasicStrategy> data){
CacheAngelConfigFromFactory.putAngel(condition, data, CacheAngelConfigFromFactory.ONLYCHECKUSEDCACHE);
Set<Angel> canUpdateAngels = AngelServiceShare.getCatAngelMap(condition.getCatId());
if(canUpdateAngels != null && canUpdateAngels.size() > 0) {
for(Angel angel : canUpdateAngels){
//找出指定类别的精灵
if(null != angel.getCategories() && angel.getCategories().contains(condition.getCatId())) {
CheckinCondition cc = CacheAngelConfigFromFactory.getCondition(condition); //重新创建一个对象,防止多个精灵公用同一个对象引用
cc.setAngelId(angel.getMedalId());
parseAngel(cc, data);
}
}
}
}
private static void parseAngel(CheckinCondition condition, Map<Long, BasicStrategy> data) {
STOP_WATCH.start();
CacheAngelConfigFromFactory.putAngel(condition, data, CacheAngelConfigFromFactory.LEGALCACHE);
STOP_WATCH.stop("generate strategey ");
}
}