[Javaer]可變參數新接觸

    今天花了N個小時作了一個如今看來十分簡單明瞭的重構,目的是少寫點代碼,緣由嘛,天然是萬惡的需求變動保密java

    原始代碼(操做的是mongo,使用spring-data):spring

 

public static void buildCountryChannelCriteria(String country, String channel,
		Query q) {
	//查詢推廣至全球以及包含參數country的app
	Criteria countryC = new Criteria();
	if (!StringUtils.isBlank(country)) {
		countryC.orOperator(Criteria.where("countries").exists(false),Criteria.where("countries." + (country.toUpperCase())).exists(true));
	} else {//國家未知  則只查詢推廣至全球的
		countryC.and("countries").exists(false);
	}
	
	Criteria channelC = new Criteria();
	//查找推薦至所有渠道以及指定渠道的app
	if (!StringUtils.isBlank(channel)) {
		channelC.orOperator(Criteria.where("channels").exists(false), Criteria.where("channels." + channel).exists(true));
	} else {//渠道未知 則只查詢推廣至全渠道的
		channelC.and("channels").exists(false);
	}
	
	q.addCriteria(new Criteria().andOperator(countryC, channelC));
}

     代碼很簡單,拼接country和channel的Criteria,兩者都有可能包含或操做(orOperator),跟sql中or查詢使用括號括起or操做來避免錯誤的查詢同樣,這裏使用new Criteria().andOperator來對兩個or操做進行and。sql

    該方法被多個外部方法調用,新需求中,外部方法也有相似or之類的操做,最開始本身設想是這樣的:mongodb

public static void buildCountryChannelCriteria(String country, String channel, Query q) {
	//...ommit
	buildCountryChannelCriteria(String country, String channel, Query q, null);//調用重構後的方法
}

public static void buildCountryChannelCriteria(String country, String channel, Query q, Criteria existedAndCriteria) {
	//...ommit
	q.addCriteria(existedAndCriteria.andOperator(countryC, channelC));
}

     可不幸的是:Due to limitations of the com.mongodb.BasicDBObject, you can't add a second 'null' criteria. Mongo查詢中貌似只容許存在一個"$and"查詢屬性,上面的代碼中existedAndCriteria在外部方法中已經有了一個$and查詢屬性,再次調用andOperator時就報錯了.......數組

 

   

   糾結N就以後,決定把外部包含or操做的Criteria傳遞進來,而後在該方法中將外部的Criteria一併傳遞給andOperator方法,因而問題又來了,andOperator這貨接受的參數是可變參數Criteria...,不過可變參數本身平時用的也不多,因此在究竟如何傳參和類型轉換上糾結了下。app

 

    最終仍是重構完成了。對於可變參數主要豐富瞭如下兩點:ui

    ①外部調用的時候能夠傳入list,而後使用list.toArray(new Criteria[list.size()])將list轉換爲數組,數組能夠直接做爲可變參數對象傳遞給andOperator方法(andOperator(new Criteria[]{})這樣調用是ok的)。spa

    ②本身在最終實現時,外部調用傳入的也是可變參數,可變參數轉換成list可使用java.util.Arrays.asList(Object[])方法,能夠將傳入的可變參數直接當作數組傳遞進去(可變參數和數組能夠直接互轉?這點還須要深刻了解)。這樣作還有個明顯的好處就是,不須要保留舊的接口了,直接調用新接口時可變參數部分能夠不指定,也就是說外部方法什麼都不用改了。甚好。code

    不過須要注意的是,asList返回的是固定長度的list,不能add,因此須要將其返回值賦給一個新array對象

 

    最終代碼:

 

/**
 * 拼接country和channel的查詢語句<br>
 * @param country
 * @param channel
 * @param q
 * @param criterias4And	其餘須要添加至andOperator的語句子句
 */
public static void buildCountryChannelCriteria(String country, String channel, 
		Query q, Criteria... criterias4And) {
	//查詢推廣至全球以及包含參數country的app
	Criteria countryC = new Criteria();
	if (!StringUtils.isBlank(country)) {
		countryC.orOperator(Criteria.where("countries").exists(false),Criteria.where("countries." + (country.toUpperCase())).exists(true));
	} else {//國家未知  則只查詢推廣至全球的
		countryC.and("countries").exists(false);
	}
	
	Criteria channelC = new Criteria();
	//查找推薦至所有渠道以及指定渠道的app
	if (!StringUtils.isBlank(channel)) {
		channelC.orOperator(Criteria.where("channels").exists(false), Criteria.where("channels." + channel).exists(true));
	} else {//渠道未知 則只查詢推廣至全渠道的
		channelC.and("channels").exists(false);
	}
	
	//組合外部條件和內部條件
	List<Criteria> cList = new ArrayList<Criteria>(0);
	if (null!=criterias4And && criterias4And.length>0) {
		cList.addAll(Arrays.asList(criterias4And));//Arrays.asList 長度不可變 因此addAll
	}
	cList.add(countryC);
	cList.add(channelC);
	
	q.addCriteria(new Criteria().andOperator(cList.toArray(new Criteria[cList.size()])));
}
//外部調用依舊是:
buildCountryChannelCriteria(country, channel, q);

 

 

 

   相關錯誤連接參考:http://www.mkyong.com/java/due-to-limitations-of-the-basicdbobject-you-cant-add-a-second-and/

相關文章
相關標籤/搜索