您好,登錄后才能下訂單哦!
本篇內容介紹了“Java項目工程實例代碼分析”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
實際上,咱們平時嘴中常說的“好”和“爛”,是對代碼質量的一種描述。“好”籠統地表示代碼質量高,“爛”籠統地表示代碼質量低。對于代碼質量的描述,除了“好”“爛”這樣比較簡單粗暴的描述方式之外,我們也經常會聽到很多其他的描述方式。這些描述方法語義更豐富、更專業、更細化。我搜集整理了一下,羅列在了下面,一般有幾下幾標準,分別是可讀性、可維護性、可擴展性、可復用性 、靈活性、可測試性等等
可讀性 readability
軟件設計大師 Martin Fowler 曾經說過:“Any fool can write code that a computer can understand. Good programmers write code that humans can understand.”翻譯成中文就是:“任何傻瓜都會編寫計算機能理解的代碼。好的程序員能夠編寫人能夠理解的代碼。”Google 內部甚至專門有個認證就叫作 Readability。只有拿到這個認證的工程師,才有資格在 code review 的時候,批準別人提交代碼。可見代碼的可讀性有多重要,畢竟,代碼被閱讀的次數遠遠超過被編寫和執行的次數。
  我個人認為,代碼的可讀性應該是評價代碼質量最重要的指標之一。我們在編寫代碼的時候,時刻要考慮到代碼是否易讀、易理解。除此之外,代碼的可讀性在非常大程度上會影響代碼的可維護性。畢竟,不管是修改 bug,還是修改添加功能代碼,我們首先要做的事情就是讀懂代碼。代碼讀不大懂,就很有可能因為考慮不周全,而引入新的 bug。
  既然可讀性如此重要,那我們又該如何評價一段代碼的可讀性呢?我們需要看代碼是否符合編碼規范、命名是否達意、注釋是否詳盡、函數是否長短合適、模塊劃分是否清晰、是否符合高內聚低耦合等等。你應該也能感覺到,從正面上,我們很難給出一個覆蓋所有評價指標的列表。這也是我們無法量化可讀性的原因。
  實際上,code review 是一個很好的測驗代碼可讀性的手段。如果你的同事可以輕松地讀懂你寫的代碼,那說明你的代碼可讀性很好;如果同事在讀你的代碼時,有很多疑問,那就說明你的代碼可讀性有待提高了
可維護性 maintainability
  一般指的是在不破壞原代碼設計的前提下,快速修改bug或增加代碼,不會帶來新bug,表明該代碼的維護性比較好。落實到編碼開發,所謂的“維護”無外乎就是修改 bug、修改老的代碼、添加新的代碼之類的工作。所謂“代碼易維護”就是指,在不破壞原有代碼設計、不引入新的 bug 的情況下,能夠快速地修改或者添加代碼。所謂“代碼不易維護”就是指,修改或者添加代碼需要冒著極大的引入新 bug 的風險,并且需要花費很長的時間才能完成。
可擴展性 extensibility
  代碼面對未來新需求的變化能力,一般來說,開發新需求的時候,不修改原代碼或很少修改,即可達到需求開發的能力,通常會預留一些功能擴展點。
可復用性 reusability
  盡量避免重復造輪子,即能夠沉淀出一些通用的代碼邏輯,保持與上層業務代碼的解耦
靈活性 flexibility
  這個詞比較寬泛。通常與可維護性、可擴展性以及可復用性類似
可測試性
  主要反映在寫單測的時候。從兩個方面體現:
1.單元測試是否容易編寫;
2.寫單元測試的時候,不能依賴環境,遠程調用其他服務的借口,盡可能進行mock數據,保持服務之間的解耦。雖然要團隊每人都按這個規范走很難,但我們團隊有一個強制要求,就是每個功能函數不能超過50行代碼,而且要求代碼越短越好。
這幾個維度是評判代碼維度比較重要的幾個指標。
  高內聚低耦合幾乎是每個程序員員都會掛在嘴邊的,但這個詞太過于寬泛,太過于正確,所以聰明的編程人員們提出了若干面向對象設計原則來衡量代碼的優劣:
開閉原則 OCP (The Open-Close Principle)
單一職責原則 SRP (Single Responsibility Principle)
依賴倒置原則 DIP (Dependence Inversion Principle)
最少知識原則 LKP (Least Knowledge Principle)) / 迪米特法則 (Law Of Demeter)
里氏替換原則 LSP (Liskov Substitution Principle)
接口隔離原則 ISP (Interface Segregation Principle)
組合/聚合復用原則 CARP (Composite/Aggregate Reuse Principle)
  這些理論想必大家都很熟悉了,是我們編寫代碼時的指導方針,按照這些原則開發的代碼具有高內聚低耦合的特性,換句話說,我們可以用這些原則來衡量代碼的優劣。
我相信每個工程師都想寫出高質量的代碼,不想一直寫沒有成長、被人吐槽的爛代碼。那如何才能寫出高質量的代碼呢?針對什么是高質量的代碼,我們剛剛講到了七個最常用、最重要的評價指標。所以,問如何寫出高質量的代碼,也就等同于在問,如何寫出易維護、易讀、易擴展、靈活、簡潔、可復用、可測試的代碼,但要寫好代碼,也不是一蹴而就,需要非常多的實踐與積累,下面簡舉例說明:
  抽象思維是我們工程師最重要的思維能力,因為軟件技術本質上就是一門抽象的藝術。我們工程師每天都要動用抽象思維,對問題域進行分析、歸納、綜合、判斷、推理,從而抽象出各種概念,挖掘概念和概念之間的關系,然后通過編程語言實現業務功能,所以,我們大部分的時間并不是在寫代碼,而是在梳理需求,理清概念,對需求有一個全局的認知。而抽像能力讓我及團隊切身感受到,它給我們在編碼和設計上帶來的質的變化。
案例一:異步Excel導出
其實導出Excel功能在我們工程里隨處可見,特別是咱們的運營希望一次性導出越多數據越好,為了不給我們系統帶來太大壓力,對于大數據量的導出一般異步進行,針對于這樣一個簡單的功能,那么應該如何抽像呢?
普通的寫法:
public String exportXXX(參數) throws Exception { //業務實現 } public String exportXXX2(參數) throws Exception { //業務實現 }
抽像寫法:
我們其實可以把每個異步導出看作是一個異步任務,而每個任務可導出的內容是不一樣的,因此完全可以把導出抽像一個方法,由每個具體實現類去實現導出不同的內容,具體如下:
// export excel public interface IExcelExportTask { String export(BizCommonExportTask exportTask) throws Exception; } //樣例實現類 XXXXExportTask implements IExcelExportTask { String export(BizCommonExportTask exportTask) throws Exception{ public String export(BizCommonExportTask exportTask) throws Exception { //組織數據篩選條件 TestReq queryReq = GsonUtils.toObject(exportTask.getInputParams(),TestReq.class); String fileName = String.format("%s%s%s", exportTask.getUploadFileName(),System.currentTimeMillis(),".xlsx"); String downUrl = excelService.uploadExcel(fileName, null, new Fetcher<PreOccupyModel>(PreOccupyModel.class) { //循環獲取數據 @Override public List<TestModel> fetch(int pageNo, int pageSize) throws OspException{ TestQueryResp resp = testFethchLogic.fetchRecord(queryReq); return pageNo > resp.getPageNum() ? Collections.emptyList() :toExcelModel(resp); } }); return downUrl; } } public class XXXXExportTask1 implements IExcelExportTask { @Override public String export(BizCommonExportTask exportTask) throws OspException { TestQuery query = GsonUtils.toObject(exportTask.getInputParams(), TestQuery .class); String fileName = String.format("%s%s%s", exportTask.getUploadFileName(), System.currentTimeMillis(), ".xlsx"); return excelService.uploadExcel(fileName, null, new Fetcher<ExportItemModel>(TestModel.class) { @Override public List<TestModel> fetch(int pageNo, int pageSize) throws OspException { return XXXXLogic.queryExportItem(query, pageNo, pageSize); } }); } } //導出任務分發器 public class ExcelTaskDispacther extends ApplicationObjectSupport { public boolean dispacthTask(Long taskId) throws OspException { updateTaskStatus(exportTask,CommonExportStatus.CREATING,TransferExportStatus.CREATING,StringUtils.EMPTY); try { String beanName = getBeanName(); ExportTaskHandler exportTaskHandler = getApplicationContext().getBean(beanName , IExcelExportTask .class); if(exportTaskHandler == null) { log.warn(String.format("任務ID[%s]寫入配置錯誤!", taskId)); return false; } updateTaskStatus(exportTask,CommonExportStatus.CREATE_SUCCESS,TransferExportStatus.CREATE_SUCCESS,StringUtils.EMPTY); log.info(String.format("任務ID[%s]RFID為[%s]處理成功", exportTask.getId(),rfid)); return true; } catch(BusiException ex) { log.info("任務ID[{}]失敗,原因:{}", exportTask.getId(),ex.getMessage(),ex); updateTaskResult(); } catch(Exception ex) { log.info("任務ID[{}]失敗,原因:{}", exportTask.getId(),ex.getMessage(),ex); updateTaskResult(); } return false; } }
案例二:系統通知
在微服務化流行的今天,為了提升系統吞吐量,系統職責越來越細,各系統模塊需要頻繁交互數據,那么對于復雜的數據交互場景,比如我們調撥單,調撥單在扭轉的過程中需要與很多系統交互,跟門店、倉庫、庫存模塊有非常多的交互,我們又該如何抽像呢,以下是調撥與各系統交互的代碼示例
//接口定義 public interface BizNotificationHandler { /** * 拋異常會當失敗處理 * 是否需要重試由BizNotificationStatus返回狀態來決定 * @param bizNotification * @return * @throws OspException */ BizNotificationStatus handleNotification(BizNotification bizNotification) throws OspException; } //推送調撥差異數據給庫存系統 public class SyncDiffToSimsAndBackQuotaHandler implements BizNotificationHandler { @Override public BizNotificationStatus handleNotification(BizNotification bizNotification) throws OspException { //業務邏輯實現 return BizNotificationStatus.PROCESS_SUCCESS; } } //占用庫存 public class TransferOccupyInventoryHandler implements BizNotificationHandler { @Override public BizNotificationStatus handleNotification(BizNotification bizNotification) throws OspException { //業務實現 } } //在GPDC生成新條碼 public class GpdcGenerateNewBarcodeHandler implements BizNotificationHandler { @Override public BizNotificationStatus handleNotification(BizNotification bizNotification) throws OspException { //業務代碼實現 } }
其實我們在與其它系統交互的時候,我們可以把每一個交互動作抽像成一個通知事件,每次交互的時候,寫一個事件通知事件即可。
  關于組合/聚合復用原則,其實我們在項目過程會經常遇到,比如項目里會經常管理各種單據,像采購單、調撥單、收貨單等,而對于每種單據都會有各種各樣的較驗,我們先來看一段建調撥單代碼,具體如何下:
//接口定義 public interface TransferValidator { boolean validator(CreateTransferCtx ctx) throws OspException; } //接口實現1 public class W2sCrossPoQtyValidator implements TransferValidator { @Override public boolean validator(CreateTransferCtx ctx) throws OspException { //較驗器代碼實現 } //接口實現2 public class W2sStoreBarcodeSaleLimitValidator implements TransferValidator { @Override public boolean validator(CreateTransferCtx ctx) throws OspException { //較驗器代碼實現 } } //較驗器組裝 public class TransferValidators { public ValidatorChain newChain() { return new ValidatorChain(); } public class ValidatorChain { private final List<TransferValidator> validators = new ArrayList<>(); public ValidatorChain qtyValidator() { validators.add(qtyValidator); return this; } public ValidatorChain transferRouteCfgValidator() { validators.add(transferRouteCfgValidator); return this; } public ValidatorChain prodValidator() { validators.add(prodValidator); return this; } public ValidatorChain w2sWarehouseStoreValidator() { validators.add(w2sWarehouseStoreValidator); return this; } public ValidatorChain w2sStoreBarcodeSaleLimitValidator() { validators.add(w2sStoreBarcodeSaleLimitValidator); return this; } public ValidatorChain w2sAssignPoValidator() { validators.add(w2sAssignPoValidator); return this; } public ValidatorChain w2sCrossPoValidator() { validators.add(w2sCrossPoValidator); return this; } public ValidatorChain w2sCrossPoQtyValidator() { validators.add(w2sCrossPoQtyValidator); return this; } public ValidatorChain w2sCross4XupValidator() { validators.add(w2sCross4XupValidator); return this; } public ValidatorChain repeatLineValidator() { validators.add(repeatLineValidator); return this; } public ValidatorChain sstradeBarcodeValidator() { validators.add(sstradeBarcodeValidator); return this; } public ValidatorChain s2wWarehouseStoreValidator() { validators.add(s2wWarehouseStoreValidator); return this; } public boolean validator(CreateTransferCtx ctx) throws OspException { for (TransferValidator validator : validators) { if (!validator.validator(ctx)) { return false; } } return true; } } } //業務代碼使用 public interface TransferCreator { boolean createOrder(CreateTransferCtx ctx) throws OspException; } public abstract class DefaultTransferCreator implements TransferCreator { @Override public boolean createOrder(CreateTransferCtx ctx) throws OspException { validator(ctx) //實現業務邏輯 } protected abstract boolean validator(CreateTransferCtx ctx) throws OspException; } //店倉調撥單 public class S2wRefundCreator extends DefaultTransferCreator { //較驗器自由組裝 @Override protected boolean validator(CreateTransferCtx ctx) throws OspException { return transferValidators.newChain() .qtyValidator() .transferRouteCfgValidator() .prodValidator() .validator(ctx); } }
“Java項目工程實例代碼分析”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。