首先描述下业务场景:A需求是,根据电话号码取会员信息,包含交易记录的信息。B需求是,根据会员id取会员信息,或根据电话号码取会员信息,但都不包括交易记录的信息。因为后一个需求是在前一个需求的设计阶段提出的,因此考虑将类似功能作为对外提供的统一接口。同时要搭建新的会员基础平台,爽啊,一切都是新的。又是一个人设计并编码,可以心随所想,泼墨挥毫,尽情尽兴,怎一个爽字了得!
分析设计:所需要的步骤有:1.根据电话号码取会员id的列表;2.根据会员id取会员基础信息;3.根据会员id取交易记录。
A需求需要1,2,3步。B需求需要2或1,2。
这么稍稍一梳理,就很清楚了,以后的业务需求大致就这些,顶多再加上根据某卡号,某*号来查找会员信息(列表)。有其他任何新的业务需求,都只要新增插件类,即插即用啊。综合以上考虑,貌似有一种现成的设计模式--建造模式可以借鉴啊。
大致过程是客户端(UserPhoneService和TmallUserService)请求导演类(MemberDirector),然后导演者操纵具体建造者(Phone400Builder和IfcBuilder)对象,开始产品的创建过程。具体建造者每接到导演者的一个指令,就按照指令向产品中增加一个零件。当产品完成后,建造者把产品返还给客户端。
客户端针对需求A和B进行请求, 在对外的client接口工程里调用UserPhoneServiceImpl和TmallUserServiceImpl,它们都调用导演类MemberDirector,A需求调用的是getPhone400Model()方法,B需求调用getIfcModelByUserId()与getIfcModelByPhone()。脉络很清晰,左边一线完成A需求,右边一线完成B需求。中间是公用的。
上面的过程就像制片人接受编剧的剧本后,指定导演。制片人也就是投资商无需过问导演调度的细节,只要导演如期交出影片就行,剩下的事情就是躺着数money。下面的工作就交给导演了,导演类根据不同制片人的需求开始进行不同的调度,一种需求要先这样再那样,另一种需求要先那样再这样,这就提纲挈领地制定了大致步骤,然后要拍A片把就启用剧组A,拍B片就启用剧组B,拍C片就启用剧组C。管你是American( 美国 )、British( 英国 )还是Chinese( 中国 )片呢,嘿嘿,反正都由各自的建造者(剧组A,B,C)去完成。
导演将任务下达到具体的剧组后,剧组内就开始按照导演规定的步骤开始行动了,联系演员,联系场地,联系道具。。。拍《新红楼梦》的先海选演员,导演说的这步要早,四大名著要演出些韵味,演员至少要懂得剧情和角色性情呀,得安排红学大家给科普下,这可是慢功夫呀。有了几百号演员也才能试服装道具呀,量体裁衣嘛。联系场地就横店了,这个比较简单放最后好了。哪部分场景的全部资源都到位了,就先拍哪部分。这个拍摄先后次序当然也是导演根据实际情况安排好了的,最后来个后期制作。一部历史大戏就搞定了。那如果要拍室内剧,比如《我爱我家》,那剧组怎么做呢,选的演员都要是能搞笑的,而且也不需要多少人,过来过去就那么几位,两位数不到。道具基本不需要准备,都是日常用品,所以这个环节就省了(到时需要什么服装啊,就从摄影师身上扒就行了,反正摄影师只拍别人不拍自己。)场地也不需要多,就是一个房间足矣,但是这个房间的准备可就有讲究了,怎么布置方便剧情、看着像温暖的家的感觉呀,这个要提早准备。 总之不同剧组按照导演的不同安排按部就班的做就行,最后提供成品影片指日可待呀。
这成品影片就是建造模式中的产品类了。虽然最终的产品仅是影片,但这可不仅仅是120分钟的电影或n级连续剧这么简单呀,我们不能仅仅从狭义的影片的角度去理解这个产品呀,这产品可是凝聚了台前幕后太多的心血了。你千万别觉得美工组没有用,又不是拍动画片,但是你知道没有他们的服装道具设计,没有他们为演员化妆,这影片里的
女星绝对不会如此光鲜亮丽,你以为林黛玉一头的贴片那么容易贴呢,没2小时还真贴不上呢,所以美工组也为最终的产品贡献着中间零件呀。世界上任何一件艺术品都是经过精雕细琢的,不论是艺术家雕饰的还是天然雕饰的。
形象吧,理解了吧,这就是建造模式中的各角色,大幕拉开,粉墨登场。。。
代码示例:
@Component
public class UserPhoneServiceImpl implements UserPhoneService {
@Autowired
private MemberDirector memberFacade;
public ReturnVO getUserByPhone(String phone, Long sellerId) {
return memberFacade.getPhone400Model().fetchMemberInfo(phone, sellerId);
}
}
@Component
public class TmallUserServiceImpl implements TmallUserService {
@Autowired
private MemberDirector memberDirector;
public ReturnVO getUserInfoByUserId(Long userId) {
return memberDirector.getIfcModelByUserId().fetchMemberInfo(userId.toString(), null);
}
@Override
public ReturnVO getUserByPhone(String phone) {
return memberDirector.getIfcModelByPhone().fetchMemberInfo(phone, null);
}
}
@Service
public class MemberDirector {
@Autowired
private Phone400Builder phone400Builder;
@Autowired
private IfcBuilder ifcBuilder;
private ArrayList<String> sequence = new ArrayList<String>();
public Phone400Model getPhone400Model() {
this.sequence.clear();
this.sequence.add(MemberConstants.GET_USER_IDS_BY_PHONE);
this.sequence.add(MemberConstants.GET_USER_INFOS);
this.sequence.add(MemberConstants.GET_ORDER_INFOS);
this.sequence.add(MemberConstants.GET_RESPONSE);
this.phone400Builder.setSequence(this.sequence);
return this.phone400Builder.getMemberModel();
}
public IfcModel getIfcModelByUserId() {
this.sequence.clear();
this.sequence.add(MemberConstants.GET_USER_IDS_BY_USER_ID);
this.sequence.add(MemberConstants.GET_USER_INFOS);
this.sequence.add(MemberConstants.GET_RESPONSE);
this.ifcBuilder.setSequence(this.sequence);
return this.ifcBuilder.getMemberModel();
}
public IfcModel getIfcModelByPhone(){
this.sequence.clear();
this.sequence.add(MemberConstants.GET_USER_IDS_BY_PHONE);
this.sequence.add(MemberConstants.GET_USER_INFOS);
this.sequence.add(MemberConstants.GET_RESPONSE);
this.ifcBuilder.setSequence(this.sequence);
return this.ifcBuilder.getMemberModel();
}
}
public abstract class MemberBuilder {
public abstract void setSequence(ArrayList<String> sequence);
public abstract MemberModel getMemberModel();
}
@Component
public class Phone400Builder extends MemberBuilder {
@Autowired
private Phone400Model phone400Model;
@Override
public Phone400Model getMemberModel() {
return this.phone400Model;
}
@Override
public void setSequence(ArrayList<String> sequence) {
this.phone400Model.setSequence(sequence);
}
}
@Component
public class IfcBuilder extends MemberBuilder {
@Autowired
private IfcModel ifcModel;
public IfcModel getMemberModel() {
return this.ifcModel;
}
@Override
public void setSequence(ArrayList<String> sequence) {
this.ifcModel.setSequence(sequence);
}
}
public abstract class MemberModel<T>{
private Logger logger = LoggerFactory.getLogger(MemberModel.class);
@Autowired
private MemberRelPhoneDAO memberRelPhoneDAO;
// 取会员信息
protected abstract ReturnVO getUserInfos(List buyerIds);
// 取订单信息。可根据不同的入参取不同的结果集,如:取该买家所有的订单记录,取该买家与某个卖家的订单记录
protected abstract ReturnVO getOrderInfos(ReturnVO returnVO);
protected abstract ReturnVO getOrderInfos(ReturnVO returnVO,Long sellerId);
// 根据请求方的不同来返回不同的数据
protected abstract ReturnVO getResponseByDiffResource(ReturnVO returnVO);
// 取淘宝会员数据
public final ReturnVO fetchMemberInfo(String paramValue,Long sellerId) {
ReturnVO returnVO = new ReturnVO();
List<Long> userIds = new ArrayList<Long>();
for (int i = 0; i < this.sequence.size(); i++) {
String actionName = this.sequence.get(i);
if (actionName.equalsIgnoreCase(MemberConstants.GET_USER_IDS_BY_PHONE)) {
userIds = this.getUserIdsByPhone(paramValue);
} else if (actionName.equalsIgnoreCase(MemberConstants.GET_USER_IDS_BY_USER_ID)) {
userIds.add(Long.parseLong(paramValue));
} else if (actionName.equalsIgnoreCase(MemberConstants.GET_USER_INFOS)) {
returnVO = this.getUserInfos(userIds);
} else if (actionName.equalsIgnoreCase(MemberConstants.GET_ORDER_INFOS)) {
returnVO = this.getOrderInfos(returnVO,sellerId);
} else if (actionName.equalsIgnoreCase(MemberConstants.GET_RESPONSE)) {
returnVO = this.getResponseByDiffResource(returnVO);
}
}
return returnVO;
}
// 根据电话号取userId的列表
protected List<Long> getUserIdsByPhone(String phone) {
return memberRelPhoneDAO.getUserIdsByPhone(phone);
}
// 这个参数是各个基本方法执行的顺序
private ArrayList<String> sequence = new ArrayList<String>();
final public void setSequence(ArrayList<String> sequence) {
this.sequence = sequence;
}
}
@Component
public class Phone400Model<T> extends MemberModel {
@Autowired
private UicReadServiceClient uicReadServiceClient;
@Autowired
private OrderServiceClient orderService;
// 根据用户id列表取用户信息
protected ReturnVO getUserInfos(List buyerIds) {
ReturnVO returnVO = new ReturnVO();
String buyerIdStr = StringUtil.join(buyerIds.toArray(), MemberConstants.REGEX);
try{
ResultDO<List<BaseUserDO>> uicResult = uicReadServiceClient.getUserInfoListByUserIds(buyerIdStr);
if (uicResult.isSuccess()) {
List<BaseUserDO> baseUserDOs = uicResult.getModule();
baseUserDOs = sortUserInfos(uicResult.getModule());
List<MultiModuleElement> multiModuleElements = new ArrayList<MultiModuleElement>();
for(BaseUserDO baseUserDO:baseUserDOs){
if(baseUserDO==null) continue;
MultiModuleElement multiModuleElement = new MultiModuleElement();
multiModuleElement.setBaseUserDO(baseUserDO);
multiModuleElements.add(multiModuleElement);
}
returnVO.setError(false);
returnVO.setModule(multiModuleElements);
return returnVO;
} else {
returnVO.setErrorCode(MemberConstants.GET_ERROR_FROM_EXTERNAL_SYSTEM);
return returnVO;
}
}catch(Exception e){
returnVO.setError(true);
returnVO.setErrorCode(MemberConstants.THROW_EXCEPTIN_BY_EXTERNAL_SYSTEM);
return returnVO;
}
}
protected ReturnVO getOrderInfos(ReturnVO returnVO,Long sellerId) {
List<MultiModuleElement> multiModuleElements = new ArrayList<MultiModuleElement>();
List<MultiModuleElement> onlyUsers = (List<MultiModuleElement>) returnVO.getModule();
try {
for(MultiModuleElement element:onlyUsers){
if(element.getBaseUserDO()==null){
returnVO.setError(true);
returnVO.setErrorCode(MemberConstants.GET_NULL_FROM_EXTERNAL_SYSTEM);
return returnVO;
}
MultiModuleElement multiModuleElement = new MultiModuleElement();
List<BizOrderDO> bizOrderDOs = new ArrayList<BizOrderDO>();
//下面是拼装查询条件
QueryBizOrderDO query = new QueryBizOrderDO();
long[] sellerNumIds = { sellerId };
query.setSellerNumId(sellerNumIds);
long[] buyerIdArr = new long[USER_SUM];
buyerIdArr[0] = element.getBaseUserDO().getUserId();
query.setBuyerNumId(buyerIdArr);
query.setIsNeedLimitQuery(true);
query.setEnableCount(true);
query.setLimitTotalNum(ORDER_SUM);
query.setPageNo(1);
query.setPageSize(ORDER_SUM);
//取订单数据
BatchQueryBizOrderResultDO mainOrderResultDO = orderService.queryBatchForBuyer(element.getBaseUserDO().getUserId(), query);
if(mainOrderResultDO.isSuccess()){
List<BizOrderDO> mainOrders = mainOrderResultDO.getBizOrderList();
mainOrders = this.sortOrderInfos(mainOrders);
for(BizOrderDO mainOrderDO:mainOrders){
BatchQueryBizOrderResultDO subOrderResultDO = orderService.getDetailByParentId(mainOrderDO.getBizOrderId(), false);
List<BizOrderDO> subOrderDOs = subOrderResultDO.getBizOrderList();
mainOrderDO.setDetailOrderList(subOrderDOs);
bizOrderDOs.add(mainOrderDO);
}
multiModuleElement.setBaseUserDO(element.getBaseUserDO());
multiModuleElement.setBizOrderDOs(bizOrderDOs);
multiModuleElements.add(multiModuleElement);
}else{
returnVO.setError(true);
returnVO.setErrorCode(MemberConstants.GET_ERROR_FROM_EXTERNAL_SYSTEM);
return returnVO;
}
}
returnVO.setError(false);
returnVO.setModule(multiModuleElements);
} catch (TCException e) {
e.printStackTrace();
returnVO.setError(true);
returnVO.setErrorCode(MemberConstants.THROW_EXCEPTIN_BY_EXTERNAL_SYSTEM);
returnVO.setErrorMsg(e.getCause() + ":" + e.getMessage());
}
return returnVO;
}
protected ReturnVO getResponseByDiffResource(ReturnVO returnVO) {
List<T> returnModel = new ArrayList<T>();
IConvertData transferWebData = TransferWebDataFactory.getInstance().createTransfer(MemberConstants.SOURCE_400);
for (Iterator iterator = ((List) returnVO.getModule()).iterator(); iterator.hasNext();) {
MultiModuleElement multiModuleElement = (MultiModuleElement) iterator.next();
T t = (T) transferWebData.convert(multiModuleElement);
returnModel.add(t);
}
returnVO.setModule(returnModel);
returnVO.setError(false);
return returnVO;
}
protected ReturnVO getOrderInfos(ReturnVO returnVO) {
return null;
}
}
@Component
public class IfcModel<T> extends MemberModel {
@Autowired
private UicReadServiceClient uicReadServiceClient;
String buyerIdStr = StringUtil.join(buyerIds.toArray(), MemberConstants.REGEX);
try{
ResultDO<List<BaseUserDO>> uicResult = uicReadServiceClient.getUserInfoListByUserIds(buyerIdStr);
if (uicResult.isSuccess()) {
List<BaseUserDO> baseUserDOs = uicResult.getModule();
if(baseUserDOs!=null&&baseUserDOs.size()>0){
returnVO.setError(false);
returnVO.setModule(baseUserDOs);
return returnVO;
}
}
returnVO.setErrorCode(MemberConstants.GET_ERROR_FROM_EXTERNAL_SYSTEM);
return returnVO;
}catch(Exception e){
returnVO.setError(true);
returnVO.setErrorCode(MemberConstants.THROW_EXCEPTIN_BY_EXTERNAL_SYSTEM);
return returnVO;
}
}
@Override
protected ReturnVO getOrderInfos(ReturnVO returnVO) {
return null;
}
@Override
protected ReturnVO getOrderInfos(ReturnVO returnVO, Long sellerId) {
return null;
}
// 家装馆业务对订单的排序规则是:按交易时间由近到远排序
protected List sortOrderInfos(List lst) {
return null;
}
@Override
protected ReturnVO getResponseByDiffResource(ReturnVO returnVO) {
List<T> returnModel = new ArrayList<T>();
IConvertData transferWebData = TransferWebDataFactory.getInstance().createTransfer(MemberConstants.SOURCE_1729);
for (Iterator iterator = ((List) returnVO.getModule()).iterator(); iterator.hasNext();) {
T t = (T) transferWebData.convert(iterator.next());
returnModel.add(t);
}
returnVO.setModule(returnModel);
returnVO.setError(false);
return returnVO;
}
}
总结:
对建造模式的深入理解:
将产品的建造过程和其零件的建造过程分割开,即将对建造过程进行指挥的责任和建造零件的责任分割开,从而可以使用同一个建造过程来生成具有不同组成零件的产品对象。
导演者将客户端创建产品的请求划分为对各个零件的建造请求,再将这些请求委派给具体建造者。使用建造模式可以使客户端不需要知道所生成的产品对象有哪些零件,每个产品的对应零件彼此有何不同,是怎样建造出来的,以及怎么样组成产品。
零件的建造过程被外部化到建造者对象里。建造者对象返还给客户端的是一个全部零件都建造完毕的产品对象。
建造模式使用多个具体建造者对象一个一个的建造出所有的零件,使用一个导演者对象来建造出完整的产品对象。