First, describe the scenario:
Our web project provides several HTTP-based post interfaces to write data to third-party users. to verify the identity of the Data writer, this interface will certainly require the other party to pass the identity. After the interface gets the identity, it will verify the identity of the writer. If it is correct, the request will be executed, and the error will return the failure information, because it is based on the same identity detection mechanism, every interface has done the same thing, as shown inCodeThere is a lot of redundant code in it. To eliminate redundant code, I can write redundant code into a function and call it in every interface. In this way, there will be a lot of repeated call statements, I think it is still not perfect. After thinking about it, I still use OO to do this. It should be noted that our language is Python, and the framework used by web projects is webpy.
Refactor the previous Code
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 ":""} '
I picked two APIs from the code to demonstrate code redundancy. These two APIs do the same thing, for example, using the tokens passed by the user) if a system query (called by getservertoken) does not match, the user is notified that the token is error, and then checks whether the token times out. Finally, the entire code is included in the try-Catch Block, once an unexpected event (such as a bug) occurs, an error message must be returned to the user. Only one piece of processing code in each API is different, in fact, the entire functional module has at least a dozen APIs, and it will continue to increase. In this case, the more APIs, the more redundant code, and the more painful it is to be modified. For example, each Catch Block is originally a return error message, and the result is later required to add the debugging status to the module. When debugging is enabled, the exception information is returned for debugging, when an exception occurs during online operation, only the regular JSON string can be returned to the user.
After Reconstruction
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 "} ' # Execute the specific code of each subclass Return Self. funpost () Except : If Debug: Raise Return ' {"Result": "error", "message ":""} ' Class Apply (openapibase ): # Inherit from 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 ): # Inherit from 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)
After reconstruction, the post function of each sub-class only handles the tasks that should be handled by itself. identity detection is all done by the parent class. Once the post function fails to pass the identity detection, the code in the subclass post is not executed at all.