首先描述下業務場景: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;
}
}
總結:
對建造模式的深入理解:
將產品的建造過程和其零件的建造過程分割開,即將對建造過程進行指揮的責任和建造零件的責任分割開,從而可以使用同一個建造過程來生成具有不同組成零件的產品對象。
導演者將客戶端創建產品的請求劃分爲對各個零件的建造請求,再將這些請求委派給具體建造者。使用建造模式可以使客戶端不需要知道所生成的產品對象有哪些零件,每個產品的對應零件彼此有何不同,是怎樣建造出來的,以及怎麼樣組成產品。
零件的建造過程被外部化到建造者對象裏。建造者對象返還給客戶端的是一個全部零件都建造完畢的產品對象。
建造模式使用多個具體建造者對象一個一個的建造出所有的零件,使用一個導演者對象來建造出完整的產品對象。