筆記一下這些年我寫的糞 code 的優化流程
一開始寫的
被檢測為 CyclomaticComplexity 。程式如下:
package work.pollochang.twgcb
import grails.gorm.transactions.Transactional
import grails.web.servlet.mvc.GrailsParameterMap
import org.hibernate.criterion.CriteriaSpecification
import org.hibernate.type.StandardBasicTypes
import work.pollochang.util.PFilterResult
import work.pollochang.util.PFilterType
/**
* TWGCB 資料處理
*/
@Transactional
class TwGcbService {
/**
* 查詢
* @param params
* @param filterType
* @return 查詢結果
*/
PFilterResult filter(
GrailsParameterMap params,
PFilterType filterType = PFilterType.DEFAULT
) {
PFilterResult pFilterResult = new PFilterResult()
params.max = (params.max ?: '10').toInteger()
params.offset = (params?.offset ?: '0').toInteger()
List<Twgcb> twgcbList = Twgcb.createCriteria().list(params) {
resultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP)
switch (filterType) {
case PFilterType.QUICK:
projections {
property('id', 'id')
property('twgcbId', 'twgcbId')
property('cname', 'cname')
property('typeDesc', 'typeDesc')
}
break
case PFilterType.FULL:
projections {
property('id', 'id')
property('twgcbId', 'twgcbId')
property('cname', 'cname')
property('type', 'type')
property('explanation', 'explanation')
property('instructions', 'instructions')
property('defaultValue', 'defaultValue')
property('remark', 'remark')
property('typeDesc', 'typeDesc')
}
break
case PFilterType.VIEW:
projections {
property('id', 'id')
property('twgcbId', 'twgcbId')
property('cname', 'cname')
property('explanation', 'explanation')
property('instructions', 'instructions')
property('defaultValue', 'defaultValue')
property('remark', 'remark')
property('typeDesc', 'typeDesc')
}
break
default:
projections {
property('twgcbId', 'twgcbId')
property('cname', 'cname')
sqlProjection("(select t.cdesc from bs_select t where t.type = 'twgcb_type' and t.code = this_.type ) typeDesc", ['typeDesc'], [StandardBasicTypes.STRING])
}
}
if (params?.twgcbId) {
eq('twgcbId',params?.twgcbId)
}
if (params?.type) {
int type = params?.type as int
eq('type',type)
}
if (params?.id) {
long id = params?.id as long
eq('id',id)
}
if (params?.cname) {
ilike('cname', "%${params?.cname}%")
}
order('twgcbId', 'asc')
} as List<Twgcb>
pFilterResult.domainList = twgcbList
pFilterResult.totalCount = twgcbList.totalCount?:0
return pFilterResult
}
}
第一次優化
將顯示欄位邏輯拉出
- 更改前
/**
* 查詢
* @param params
* @param filterType
* @return 查詢結果
*/
PFilterResult filter(
GrailsParameterMap params,
PFilterType filterType = PFilterType.DEFAULT
) {
// 程式碼部份省略
switch (filterType) {
case PFilterType.QUICK:
projections {
property('id', 'id')
property('twgcbId', 'twgcbId')
property('cname', 'cname')
property('typeDesc', 'typeDesc')
}
break
case PFilterType.FULL:
projections {
property('id', 'id')
property('twgcbId', 'twgcbId')
property('cname', 'cname')
property('type', 'type')
property('explanation', 'explanation')
property('instructions', 'instructions')
property('defaultValue', 'defaultValue')
property('remark', 'remark')
property('typeDesc', 'typeDesc')
}
break
case PFilterType.VIEW:
projections {
property('id', 'id')
property('twgcbId', 'twgcbId')
property('cname', 'cname')
property('explanation', 'explanation')
property('instructions', 'instructions')
property('defaultValue', 'defaultValue')
property('remark', 'remark')
property('typeDesc', 'typeDesc')
}
break
default:
projections {
property('twgcbId', 'twgcbId')
property('cname', 'cname')
sqlProjection("(select t.cdesc from bs_select t where t.type = 'twgcb_type' and t.code = this_.type ) typeDesc", ['typeDesc'], [StandardBasicTypes.STRING])
}
}
// 程式碼部份省略
}
- 更改後
/**
* 查詢
* @param params
* @param filterType
* @return 查詢結果
*/
PFilterResult filter(
GrailsParameterMap params,
PFilterType filterType = PFilterType.DEFAULT
) {
// 程式碼部份省略
switch (filterType) {
case PFilterType.QUICK:
Closure projection = (Closure) quickProjection.clone()
projection.delegate = delegate
projection()
break
case PFilterType.FULL:
Closure projection = (Closure) fullProjection.clone()
projection.delegate = delegate
projection()
break
case PFilterType.VIEW:
Closure projection = (Closure) viewProjection.clone()
projection.delegate = delegate
projection()
break
default:
Closure projection = (Closure) defaultProjection.clone()
projection.delegate = delegate
projection()
}
// 程式碼部份省略
}
/**
* 快速顯示欄位
*/
private Closure quickProjection = {
}
/**
* 完整顯示欄位
*/
private Closure fullProjection = {
}
/**
* 檢視單筆資料欄位
*/
private Closure viewProjection = {
}
/**
* 預設顯示欄位
*/
private Closure defaultProjection = {
}
將查詢條件修飾
- 更改前
/**
* 查詢
* @param params
* @param filterType
* @return 查詢結果
*/
PFilterResult filter(
GrailsParameterMap params,
PFilterType filterType = PFilterType.DEFAULT
) {
// 程式碼部份省略
if (params?.twgcbId) {
eq('twgcbId',params?.twgcbId)
}
if (params?.type) {
int type = params?.type as int
eq('type',type)
}
if (params?.id) {
long id = params?.id as long
eq('id',id)
}
if (params?.cname) {
ilike('cname', "%${params?.cname}%")
}
// 程式碼部份省略
}
- 更改後
/**
* 查詢
* @param params
* @param filterType
* @return 查詢結果
*/
PFilterResult filter(
GrailsParameterMap params,
PFilterType filterType = PFilterType.DEFAULT
) {
// 程式碼部份省略
params.each { key, value ->
if(value){
switch (key) {
case 'twgcbId':
eq('twgcbId', value)
break
case 'type':
eq('type',value as int)
break
case 'id':
eq('id', value as long)
break
case 'cname':
ilike('cname', "%${value}%")
break
}
}
}
// 程式碼部份省略
}
完整程式碼如下
package work.pollochang.twgcb
import grails.gorm.transactions.Transactional
import grails.web.servlet.mvc.GrailsParameterMap
import org.hibernate.criterion.CriteriaSpecification
import org.hibernate.type.StandardBasicTypes
import work.pollochang.util.PFilterResult
import work.pollochang.util.PFilterType
/**
* TWGCB 資料處理
*/
@Transactional
class TwGcbService {
/**
* 查詢
* @param params
* @param filterType
* @return 查詢結果
*/
PFilterResult filter(
GrailsParameterMap params,
PFilterType filterType = PFilterType.DEFAULT
) {
PFilterResult pFilterResult = new PFilterResult()
params.max = (params.max ?: '10').toInteger()
params.offset = (params?.offset ?: '0').toInteger()
List<Twgcb> twgcbList = Twgcb.createCriteria().list(params) {
resultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP)
switch (filterType) {
case PFilterType.QUICK:
Closure projection = (Closure) quickProjection.clone()
projection.delegate = delegate
projection()
break
case PFilterType.FULL:
Closure projection = (Closure) fullProjection.clone()
projection.delegate = delegate
projection()
break
case PFilterType.VIEW:
Closure projection = (Closure) viewProjection.clone()
projection.delegate = delegate
projection()
break
default:
Closure projection = (Closure) defaultProjection.clone()
projection.delegate = delegate
projection()
}
params.each { key, value ->
if(value){
switch (key) {
case 'twgcbId':
eq('twgcbId', value)
break
case 'type':
eq('type',value as int)
break
case 'id':
eq('id', value as long)
break
case 'cname':
ilike('cname', "%${value}%")
break
}
}
}
order('twgcbId', 'asc')
} as List<Twgcb>
pFilterResult.domainList = twgcbList
pFilterResult.totalCount = twgcbList.totalCount?:0
return pFilterResult
}
/**
* 快速顯示欄位
*/
private Closure quickProjection = {
projections {
property('id', 'id')
property('twgcbId', 'twgcbId')
property('cname', 'cname')
property('typeDesc', 'typeDesc')
}
}
/**
* 完整顯示欄位
*/
private Closure fullProjection = {
projections {
property('id', 'id')
property('twgcbId', 'twgcbId')
property('cname', 'cname')
property('type', 'type')
property('explanation', 'explanation')
property('instructions', 'instructions')
property('defaultValue', 'defaultValue')
property('remark', 'remark')
property('typeDesc', 'typeDesc')
}
}
/**
* 檢視單筆資料欄位
*/
private Closure viewProjection = {
projections {
property('id', 'id')
property('twgcbId', 'twgcbId')
property('cname', 'cname')
property('explanation', 'explanation')
property('instructions', 'instructions')
property('defaultValue', 'defaultValue')
property('remark', 'remark')
property('typeDesc', 'typeDesc')
}
}
/**
* 預設顯示欄位
*/
private Closure defaultProjection = {
projections {
property('twgcbId', 'twgcbId')
property('cname', 'cname')
sqlProjection("(select t.cdesc from bs_select t where t.type = 'twgcb_type' and t.code = this_.type ) typeDesc", ['typeDesc'], [StandardBasicTypes.STRING])
}
}
}
第二次優化
優化 projection 程式片段
/**
* 查詢
* @param params
* @param filterType
* @return 查詢結果
*/
PFilterResult filter(
GrailsParameterMap params,
PFilterType filterType = PFilterType.DEFAULT
) {
// 程式碼部份省略
switch (filterType) {
case PFilterType.QUICK:
Closure projection = (Closure) quickProjection.clone()
projection.delegate = delegate
projection()
break
case PFilterType.FULL:
Closure projection = (Closure) fullProjection.clone()
projection.delegate = delegate
projection()
break
case PFilterType.VIEW:
Closure projection = (Closure) viewProjection.clone()
projection.delegate = delegate
projection()
break
default:
Closure projection = (Closure) defaultProjection.clone()
projection.delegate = delegate
projection()
}
// 程式碼部份省略
}
/**
* 查詢
* @param params
* @param filterType
* @return 查詢結果
*/
PFilterResult filter(
GrailsParameterMap params,
PFilterType filterType = PFilterType.DEFAULT
) {
// 程式碼部份省略
Closure projection = getProjectionClosure(filterType)
if (projection) {
projection.delegate = delegate
projection()
}
// 程式碼部份省略
}
/**
* 依 定義查詢種類 回傳查詢顯示欄位
* @param filterType 定義查詢種類
* @return 查詢顯示欄位
*/
private Closure getProjectionClosure(PFilterType filterType) {
switch (filterType) {
case PFilterType.QUICK:
return quickProjection
case PFilterType.FULL:
return fullProjection
case PFilterType.VIEW:
return viewProjection
default:
return defaultProjection
}
}
完整程式碼如下
package work.pollochang.twgcb
import grails.gorm.transactions.Transactional
import grails.web.servlet.mvc.GrailsParameterMap
import org.hibernate.criterion.CriteriaSpecification
import org.hibernate.type.StandardBasicTypes
import work.pollochang.util.PFilterResult
import work.pollochang.util.PFilterType
/**
* TWGCB 資料處理
*/
@Transactional
class TwGcbService {
/**
* 查詢
* @param params
* @param filterType
* @return 查詢結果
*/
PFilterResult filter(
GrailsParameterMap params,
PFilterType filterType = PFilterType.DEFAULT
) {
PFilterResult pFilterResult = new PFilterResult()
params.max = (params.max ?: '10').toInteger()
params.offset = (params?.offset ?: '0').toInteger()
List<Twgcb> twgcbList = Twgcb.createCriteria().list(params) {
resultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP)
Closure projection = getProjectionClosure(filterType)
if (projection) {
projection.delegate = delegate
projection()
}
params.each { key, value ->
if(value){
switch (key) {
case 'twgcbId':
eq('twgcbId', value)
break
case 'type':
eq('type',value as int)
break
case 'id':
eq('id', value as long)
break
case 'cname':
ilike('cname', "%${value}%")
break
}
}
}
order('twgcbId', 'asc')
} as List<Twgcb>
pFilterResult.domainList = twgcbList
pFilterResult.totalCount = twgcbList.totalCount?:0
return pFilterResult
}
/**
* 依 定義查詢種類 回傳查詢顯示欄位
* @param filterType 定義查詢種類
* @return 查詢顯示欄位
*/
private Closure getProjectionClosure(PFilterType filterType) {
switch (filterType) {
case PFilterType.QUICK:
return quickProjection
case PFilterType.FULL:
return fullProjection
case PFilterType.VIEW:
return viewProjection
default:
return defaultProjection
}
}
/**
* 快速顯示欄位
*/
private Closure quickProjection = {
projections {
property('id', 'id')
property('twgcbId', 'twgcbId')
property('cname', 'cname')
property('typeDesc', 'typeDesc')
}
}
/**
* 完整顯示欄位
*/
private Closure fullProjection = {
projections {
property('id', 'id')
property('twgcbId', 'twgcbId')
property('cname', 'cname')
property('type', 'type')
property('explanation', 'explanation')
property('instructions', 'instructions')
property('defaultValue', 'defaultValue')
property('remark', 'remark')
property('typeDesc', 'typeDesc')
}
}
/**
* 檢視單筆資料欄位
*/
private Closure viewProjection = {
projections {
property('id', 'id')
property('twgcbId', 'twgcbId')
property('cname', 'cname')
property('explanation', 'explanation')
property('instructions', 'instructions')
property('defaultValue', 'defaultValue')
property('remark', 'remark')
property('typeDesc', 'typeDesc')
}
}
/**
* 預設顯示欄位
*/
private Closure defaultProjection = {
projections {
property('twgcbId', 'twgcbId')
property('cname', 'cname')
sqlProjection("(select t.cdesc from bs_select t where t.type = 'twgcb_type' and t.code = this_.type ) typeDesc", ['typeDesc'], [StandardBasicTypes.STRING])
}
}
}