這里我們會(huì)給出一個(gè)WEB開發(fā)項(xiàng)目的代碼實(shí)例,采用的框架是webpy,語言是Python。后面會(huì)給大家看到重構(gòu)之后的代碼樣例。
我們的Web項(xiàng)目提供了若干個(gè)基于HTTP協(xié)議的POST接口,用于給第三方的用戶寫入數(shù)據(jù),為了驗(yàn)證寫入數(shù)據(jù)者的身份,這樣的接口肯定會(huì)要求對(duì)方傳遞身份標(biāo)識(shí),接口得到標(biāo)識(shí)以后會(huì)驗(yàn)證寫入者的標(biāo)識(shí),正確就執(zhí)行請(qǐng)求,錯(cuò)誤就返回失敗信息,由于是基于同樣的檢測身份的機(jī)制,每個(gè)接口都做了同樣的事情,體現(xiàn)在代碼里就有大量的冗余代碼,如果要消除冗余代碼,我可以把冗余代碼寫成一個(gè)函數(shù),在每一個(gè)接口里調(diào)用,這樣的話,也會(huì)有大量重復(fù)的調(diào)用語句,感覺還是不完美,于是思考之后還是借助OO來做這個(gè)事情,需要說明的是,我們的語言是python,web項(xiàng)目采用的框架是webpy。
重構(gòu)之前的代碼
class Apply:
def POST(self):
try:
wi = web.input()
token = wi.token
projectId = wi.projectId
serverToken = getServerToken(db,token)
if serverToken == None:
return '{"result":"error","message":"token is error"}'
if checkExpires(serverToken):
return '{"result":"error","message":"token is expires"}'
userId = serverToken.userId
result = create.joinProject(userId,int(projectId))
if result[0] == True:
return '{"result":"ok","message":"ok"}'
else:
return '{"result":"error","message":"%s"}' %(result[1])
except:
if DEBUG:
raise
return '{"result":"error","message":""}'
class AddFolder:
def POST(self):
try:
wi = web.input()
token = wi.token
serverToken = getServerToken(db,token)
if serverToken == None:
return '{"result":"error","message":"token is error"}'
if checkExpires(serverToken):
return '{"result":"error","message":"token is expires"}'
userId = serverToken.userId
folderName = wi.folderName
pFolderId = int(wi.pFolderId) if hasattr(wi,"pFolderId") else 0
projectId = util.unhash17(int(wi.projectId)) if hasattr(wi,"projectId") else 0
folderId,deep,msg = tn.newFolder(db,folderName,userId,pFolderId,0,projectId)
if folderId > 0:
return '{"result":"ok","message":"%s","folderId":"%s","deep":"%s"}' %(msg,folderId,deep)
else:
return '{"result":"error","message":"%s","folderId":"%s","deep":"%s"}' %(msg,folderId,deep)
except:
if DEBUG:
raise
return '{"result":"error","message":""}'
我從代碼里挑了兩個(gè)API來展現(xiàn)代碼冗余的情況,這兩個(gè)API里做了很多一樣的事情,例如使用用戶傳過來的token(身份標(biāo)識(shí))去系統(tǒng)查詢(getServerToken調(diào)用)一旦不匹配告訴用戶token is error,然后繼續(xù)檢查token是否超時(shí),最后,整個(gè)代碼是包含在try-catch塊中,一旦有意外的事情(例如BUG)發(fā)生,需要返回錯(cuò)誤信息給用戶,只有每個(gè)API中間一塊的處理代碼是不一樣的,這還是兩個(gè)API,實(shí)際上整個(gè)功能模塊至少有十幾個(gè)API,而且還會(huì)繼續(xù)增加,那么這種情況下,API越多則冗余代碼越多,并且一旦需要修改就很痛苦,例如,每個(gè)catch塊原來就是return出錯(cuò)誤信息,結(jié)果后來要求給模塊增加調(diào)試狀態(tài),在打開調(diào)試的時(shí)候返回異常信息用于調(diào)試,上線時(shí)異常時(shí)則只能返回規(guī)矩的JSON字符串給用戶
重構(gòu)以后
class OpenApiBase:
def __init__(self):
self.funPOST = self.POST
self.POST = self.post
def post(self):
try:
wi = web.input()
token = wi.token
self.serverToken = getServerToken(db,token)
web.debug(str(self.serverToken))
if self.serverToken == False:
return '{"result":"error","message":"token is error"}'
if checkExpires(self.serverToken):
return '{"result":"error","message":"token is expires"}'
#執(zhí)行每個(gè)子類具體的代碼
return self.funPOST()
except:
if DEBUG:
raise
return '{"result":"error","message":""}'
class Apply(OpenApiBase):#繼承OpenApiBase
def POST(self):
wi = web.input()
projectId = wi.projectId
userId = self.serverToken.userId
result = create.joinProject(userId,int(projectId))
if result[0] == True:
return '{"result":"ok","message":"ok"}'
else:
return '{"result":"error","message":"%s"}' %(result[1])
class AddFolder(OpenApiBase):#繼承OpenApiBase
def POST(self):
wi = web.input()
userId = self.serverToken.userId
folderName = wi.folderName
pFolderId = int(wi.pFolderId) if hasattr(wi,"pFolderId") else 0
projectId = util.unhash17(int(wi.projectId)) if hasattr(wi,"projectId") else 0
folderId,deep,msg = tn.newFolder(db,folderName,userId,pFolderId,0,projectId)
if folderId > 0:
return '{"result":"ok","message":"%s","folderId":"%s","deep":"%s"}' %(msg,folderId,deep)
else:
return '{"result":"error","message":"%s","folderId":"%s","deep":"%s"}' %(msg,folderId,deep)
重構(gòu)以后,每個(gè)子類的POST函數(shù)只做自己應(yīng)該處理的事情,對(duì)于身份的檢測全部交給父類完成,一旦沒通過身份檢測,子類POST里的代碼根本就不會(huì)被執(zhí)行