1. 程式人生 > >學員會診之01:那些典型的面向物件錯誤

學員會診之01:那些典型的面向物件錯誤

       我原本不想用“錯誤”二字。因為錯誤顯得太嚴重了,並且,軟體編碼本身就沒有對錯,只要你把功能實現了,剩下的就是思想流派的分歧。但這裡仍舊想用“錯誤”兩個字,因為本篇診斷所涉及的那些問題基本已經屬於當前軟體開發規則中的普適需要避免的。

       注意,被診斷的學員並不是學的差的學員,相反,他有可能是學的很好的那一個,今天要診斷的劉同學,就是這樣的一位同學。劉同學來到最課程學習已經50天了,以下是他的學習記錄:

       看到沒有,分數基本都在99分左右,然後到了大作業這裡……,80分。我當時跟劉同學是這麼說的:基本上,面向物件編碼過程中所犯的那些錯誤,你都犯了。當然,再次說明,劉同學到目前為止的學習都是非常棒的,不信你看他過去這幾周發的博文,我相信,已經畢業的同學中都沒有幾個能達到他這樣的理解力度:

       現在,讓我們言歸正傳,看看劉同學在面向物件的作業(作業地址:最課程階段大作業02:實現自己的利息計算器)中,都犯了那些錯誤。

1. 獲取原始碼

       我們的第一個作業,就要求學員自己搭建原始碼伺服器(SVN),所以第一件事情,既然我們要批改作業,那就得從原始碼伺服器上去簽出程式碼。過程如下:

       首先,new->other,

 

       其次,選擇project from svn,

       緊接著,輸入SVN地址,以及使用者名稱和密碼,同時注意勾選Save authentication,

       直接點選finish,

       再次點選finish,

       選擇簽出為Java Project,

       輸入本地專案地址,注意:跟伺服器上保持一致,

       以下就是我們順利簽出的專案。先欣賞一下程式碼吧,是不是第一感覺還不錯:

2. 原始碼分析

       劉同學的原始碼,一共分為3個檔案,分別為:

       InterestCalculator.java:利息計算主類,相關業務邏輯在此處;

       InterestCalculatorTester.java:測試類,main函式入口;

       Utility.java:工具類,主要用於處理鍵盤輸入;

       這一眼看上去,很不錯,每個類各司其職。同時,執行結果也不錯,如下:

       但是,我看到這份原始碼,首先第一個就去找判斷利息計算方式的程式碼,結果發現瞭如下的程式碼:

       於是,我問劉同學的第一個問題就來:“假設我此刻需要增加一種利息計算方式,該怎麼辦?”。

       劉同學的回答是:再增加一個case!

3. 違反開閉原則(OpenClosedPrinciple,OCP

       咳咳,“再增加一個case”,恰恰就犯了第一個錯誤:違反開閉原則。

       所謂“開閉原則”,就是“對擴充套件開放,對修改關閉”。這要怎麼講?初次接觸此概念的同學,很可能一臉懵逼,

二臉還是懵逼……

       我們先來說:對修改關閉。什麼是對修改關閉?就是,對於利息計算來說,當一種計算方式被髮明出來後,它的演算法就再也沒有變過。所以,一種演算法對應一個Java類,那麼,演算法寫完成後,這個類就不應該需要再修改了。

       那什麼是:對擴充套件開放?就是,你的程式當前支援3種利息計算方式,但隨著時代跟進,也許增加了一種計算方式,那程式碼必須得很方便的擴充套件。那什麼是方便的擴充套件呢?其中一種方式就是:增加一個子類。

       所以,想明白沒有?當前的這個switch可以重構為一個抽象工廠,同時,演算法本身應該有繼承體系,大致如下:

package com.zuikc.intesters;

import java.util.LinkedList;

public abstract class InterestCalculator {
    // 本金
    protected double principal;
    // 期限(月數)
    protected int numberOfPeriods;
    // 年利率
    protected double interestRate;
    // 總利息
    protected double totalInterests;
    // 本息合計
    protected double totalToPay;
    // 用於儲存計算結果,即還款計劃
    protected LinkedList<PayPlan> results = new LinkedList<>();
    
    public InterestCalculator(double principal, int numberOfPeriods, double interestRate){
        this.principal = principal;
        this.numberOfPeriods = numberOfPeriods;
        this.interestRate = interestRate;
    }
    
    // 獲取輸入並且計算
    public void inputAndCalculate(){
        getData();
         calculate();
    }
    
    // 利息計算,由子類去實現
    abstract void calculate();
    
    private void getData(){
        // 獲取鍵盤輸入,這裡也可以提煉一個工具類;
        // 從鍵盤輸入的值儲存到本金,期限,年利率
    }
}

       注意,三個演算法就是三個子類。

       在上文中,還有一個PayPlan,它是一個實體類,裡面有一些屬性,用來表示每個月的還款資訊。

4. 違反單一職責原則(SingleResponsibilityPriciple,SRP

       在面向物件的開發中,我們還有另外一個原則,叫做:單一職責原則(Single Responsibility Priciple,SRP),簡單來說,就是一個類只完成一件事情。

       而在劉同學的程式碼中,我們可以看到InterestCalculator幹了非常多的事情,

       有負責獲取輸入的,有負責進行結果匯出的,有負責利息計算的(還包好了三種計算),甚至有對結果進行加密解密的(雖然部分實現是在Utility中)。可是這樣就會導致:一眼望去,就是妻妾太多,遲早要出事。

       匯入匯出重構出來一個類;

       加解密重構出來一個類;

       負責利息計算的,更不要說了;

5. 單個方法行數太多

       一種觀點是,單個方法不要超過30行。為什麼會有30行這個數字呢?那是因為早期的顯示器,如果你的程式碼超過30行,就超過一屏的顯示了,而我們閱讀程式碼,最好是一螢幕內顯示完畢。

如果一個方法在一屏內顯示不完,在大多數情況下,這意味著你需要將當前方法重構為兩個方法。

6. 不應將輸出固定格式

       我們在作業之中要求結果是輸出到控制檯的,於是劉同學將整個結果儲存到了一個字串中,如下:

       那麼問題又來了:假設我們現在要輸出為HTML格式怎麼辦?

       我們會發現,整個計算的過程必須全部修改。

       正確的做法是,我們將計算結果儲存到物件或者物件列表中,就像上文我重構的InterestCalculator一樣。這樣做的一個好處是,當我們需要將結果以不同的格式進行輸出的話,我們只需要提取物件的屬性就可以。

7. 其它問題

       其它問題不多了。如果其它問題過多的話,我估計劉同學要鬱悶的。但是,不過,當然,確實還存在另一個比較嚴重的問題:對稱加密。

       本次作業,幾乎所有的同學都自己實現了一個對稱加密的演算法。但這是有問題的。由於這個議題相對來說比較獨立,所以,讓我們在下一篇中詳細指出。

8. 提交修改

       我們在劉同學的程式碼上進行了一些修改,讓我們進行簽入吧。

       寫上comment,

       好了,診斷結束,讓我們給出劉同學的本次作業的會診單吧。

最課程學員會診單

華麗分割線

===========================================================

最課程JavaEE+網際網路分散式新技術開班進行中,來http://www.zuikc.com看看吧。你想參加不一樣的培訓班,並且一畢業就NB,那就來加入我們吧;

更多技術文章和開班資訊請加入,

QQ群:

相關推薦

學員會診01那些典型面向物件錯誤

       我原本不想用“錯誤”二字。因為錯誤顯得太嚴重了,並且,軟體編碼本身就沒有對錯,只要你把功能實現了,剩下的就是思想流派的分歧。但這裡仍舊想用“錯誤”兩個字,因為本篇診斷所涉及的那些問題基本已經屬於當前軟體開發規則中的普適需要避免的。        注意,被診斷的學員並不是學的差的學員,相反,他有

學員會診04你為什麼找不到工作?

我有一段時間看到文同學和潘同學比較的窩火,明明學的也還不錯,卻老是跟我說找不到工作。 先說說文同學。文同學很有意思,剛畢業那會面試機會還蠻多,並且沒兩天還拿下一個offer:某個小軟體公司讓他去做架構師~~。當然他面試的職位是Java工程師,一下子沒發揮好,吹的太厲害了,對方直接讓他上來做架構師~~~。那他

學員會診03你那慘不忍睹的三層架構

        最近檢查作業,雖然我們反覆強調三層架構就是:表示層、業務邏輯層、資料訪問層,每個層只做自己應該做的事情,但是,部分同學的作業還是不理想啊~~~         你以為的三層架構是這樣的:         而實際上你的三層架構是這樣的:         如果我們尚不能完全瞭解把握各

學員會診02SVN協作以及Page類的設計

三層架構的學生管理系統是我們第一個稍微大型的專案:分層、一個解決方案多個Project,所以值得我們停下來好好審查審查。 1.測試SVN伺服器地址 我們的作業要求學員建立自己的SVN伺服器,並且將程式碼commit上去,然後講師進行批改是從原始碼伺服器上獲取程式碼,繼而review。這非常類似於敏捷開

最課程階段大作業01使用SVN實現版本控制

       版本控制在友軍那裡都是放在整個培訓的最後階段才開始講的,但我們打算放到SE階段。與其匆匆在專案實戰階段弄個半生不熟,然後進入實際工作中接受他人對你的懷疑,不如……早死早超生~~~。        可是,我們畢竟現在才剛學了Java一個月,程式碼都寫的不溜呢,甚至都不知道目前掌握的知識能做點撒實

Java全棧程式設計師01做個Linux下的程式猿

       Windows10正在成為史上口碑最差的Windows系統 (圖侵刪)        我曾經花了數次1小時去尋找解決方案去關閉自動更新,包括停掉服務、修改登錄檔等等。但是都沒有成功。        微軟自身是知道這個問題的,但就跟過去幾年的很多微軟的技術框架一樣,我就是一意孤行,你能把

遊戲人生(一),我的lua那些坑爹的CCBReaderLoad

首先,我們說說這個CCBReaderLoad。這個指令碼是cocos2dx自帶的一個lua+cocosbuilder 的工具,具體功能吶,往下看。 先來看下我遇到的一個問題: ————美工給了我一個.ccbi檔案,讓我放到遊戲裡去。 然後我們說說這個ccbi。ccbi是co

golang教程多型性-Go面向物件

文章目錄 多型性-Go面向物件 使用介面的多型性 在上述計劃中新增新的收入流 多型性-Go面向物件 https://golangbot.com/polymorphism/ Go中的多型性是在介面

“陶華碧”該不該融資系列坐莊的方程式,錯誤的市值管理是怎樣毀滅創業者的

http://www.eeo.com.cn/2018/1121/341590.shtml “陶華碧”該不該融資系列之二:坐莊的方程式,錯誤的市值管理是怎樣毀滅創業者的 2018-11-21     經濟觀察網   鄒衛國/文    近日

Swift 中的面向協議程式設計是否優於面向物件程式設計?

作者:Andrew Jaffee,原文連結,原文日期:2018/03/28 譯者:陽仔;校對:numbbbbb,Lision;定稿:Forelax 在本文中,我們將深入討論 Swift 4 中的面向協議程式設計。這是一個系列兩篇文章中的第二篇。如果你還沒有讀過 前一篇介紹文章,請在繼續閱讀本文之前

每日一題詳解面向物件

面向物件與面向過程 最初,軟體開發所使用的思想都是面向過程,面向過程的模式更適合計算機運算,或者說更貼近於人類大腦的理解模式。然而隨著時代的發展,軟體系統也越來越複雜,規模越來越大,面向過程的弊端逐漸顯現出來,最關鍵的在於面向過程開發出的軟體系統更難維護,程式碼耦合度較高,當需求變更後,每次都需要修改大量的程

知識點好吧Python的面向物件程式設計學習

     Python的可用性及優勢相信懂的都知道,在這裡我就不過多贅述了,總之一句話人生苦短,我用Python。 基本概念理解 面向物件程式設計——Object Oriented Programming,簡稱OOP,是一種程式設計思想。OOP把物件作為程式的基本單元,一

golang教程組合代替繼承-Go面向物件

組合代替繼承-Go面向物件 Go不支援繼承,但它確實支援組合。 組合的通用定義是“放在一起”。 組合的一個例子是汽車。 汽車由車輪,發動機和各種其他部件組成。 通過嵌入結構組成 Go中的組合可以通過將一種結構型別嵌入另一種結構型別來實現。 部落格文章是一個完

Java學習路 第五章 面向物件(1)

面向物件(1) 1、認識物件 (1)萬物皆物件。 (2)物件=特點或特徵(屬性)+行為或(方法)。 (3)物件由屬性和方法組成,一定要具體到個體上。 2、認識類 (1)類是一些具有共同屬性和方法的物件的一個抽象。 (2)類是一個概念,不是具體的一個物件。 (3)

JAVA面試題2什麼是面向物件

面向物件是一種思想,世間萬物都可以看做一個物件,這裡只討論面向物件程式設計(OOP),Java是一個支援併發、基於類和麵向物件的計算機程式語言,面向物件軟體開發的優點: 程式碼開發模組化,更易維護和修改; 程式碼複用性強; 增強程式碼的可靠性和靈活性; 增加程式碼的可讀性。 面向物件的四大基本特

從零開始學 Web JavaScript(五)面向物件

大家好,這裡是「 Daotin的夢囈 」從零開始學 Web 系列教程。此文首發於「 Daotin的夢囈 」公眾號,歡迎大家訂閱關注。在這裡我會從 Web 前端零基礎開始,一步步學習 Web 相關的知識點,期間也會分享一些好玩的專案。現在就讓我們一起進入 Web 前端學習的冒險之旅吧! 一、面向物件 1、

libgdx APIAIAI讓遊戲物件思考

GdxAI是libgdx的一個AI庫,裡面有各種AI系統和演算法,包括有限狀態機,狀態樹,行為演算法(追逐,躲避...群聚),路徑演算法。基於Message和Scheduler兩種事件驅動機制。這絕對是個好東西,但要講這些知識的話,就不是侷限於libgdx這個平臺了,AI演

jackson學習WRAP_ROOT_VALUE(root物件

### 歡迎訪問我的GitHub [https://github.com/zq2599/blog_demos](https://github.com/zq2599/blog_demos) 內容:所有原創文章分類彙總及配套原始碼,涉及Java、Docker、Kubernetes、DevOPS等; ### 系

4、【Python】Python 3入門(模組/面向物件/錯誤和異常/檔案操作/序列化/命名規範)

一、模組     編寫模組有很多種方法,其中最簡單的一種便是建立一個包含函式與變數、以 .py 為字尾的檔案。     另一種方法是使用撰寫 Python 直譯器本身的本地語言來編寫模組。舉例來說,你可以使用 C 語言來撰寫 Python 模組,並且在編譯後,你可以通過標準 Pyth

【2017-07-01】Linux應用開發工程師面試問題記錄關於結構體的大小及內存對齊問題

偶數 而且 strong span net 但是 開發 f11 flag Tencent後臺服務器開發有一道題是計算一個結構體的sizeof的大小: struct strData { int m_Int; char m_Char; short m_Short; char