隨筆-19  評論-128  文章-1  trackbacks-0

          以子類取代類型編碼

           Replace Type Code with Subclasses

          1. 何謂重構

           

          1.1名詞解釋

            對軟件內部結構的一種調整,目的是在不改變「軟件之可察行為」前提下,提高其可理解性,降低其修改成本。

            

          1.2動詞解釋

            使用一系列重構準則(手法),在不改變「軟件之可察行為」前提下,調整其結構。

           

          2. 為何重構

           

          2.1「重構」改進軟件設計

            同樣完成一件事,設計不良的程序往往需要更多代碼,這常常是因為代碼在不同的方使用完全相同的語句做同樣的事。因此改進設計的一個重要方向就是消除重復代碼(Duplicate Code)

           

          2.2「重構」使軟件更易被理解

            你的源碼還有其它讀者:數個月之后可能會有另一位程序員嘗試讀懂你的代碼并做一些修改。我們很容易忘記這第二位讀者,但他才是最重要的。計算器是否多花了數個鐘頭進行編譯,又有什么關系呢?如果一個程序員花費一周時間來修改某段代碼,那才關系重大— 如果他理解你的代碼,這個修改原本只需一小時

           

          2.3「重構」助你找到臭蟲 ( bugs)

            Kent Beck 經常形容自己的一句話:『我不是個偉大的程序員;我只是個有著些優秀習慣的好程序員而已?!恢貥嬆軌驇椭腋行У貙懗鰪姽谭€?。╮obust)的代碼。 

           

          2.4「重構」助你提高編程速度

            終于,前面的一切都歸結到了這最后一點:重構幫助你更快速地開發程序。聽起來有違反直覺。當我談到重構,人們很容易看出它能夠提高質量。改善設計、提升可讀性、減少錯誤,這些都是提高質量。但這難道不會降低開發速度嗎?我強烈相信:良好設計是快速軟件開發的根本。事實上擁有良好設計才可能達成快速的開發。如果沒有良好設計,或許某段時間內你的進展迅速,但惡劣的設計很快就讓你的速度慢來。你會把時間花在調試面,無法添加新功能。修改時間愈來愈長,因為你必須花愈來愈多的時間去理解系統、尋找重復代碼。隨著你給最初程序打上一個又一個的補丁(patch),新特性需要更多代碼才能實現。真是個惡性循環。

           

          3.何時重構?

            重構本來就不是一件「特別撥出時間做」的事情,重構應該隨時隨地進行。你不應該為重構而重構,你之所以重構,是因為你想做別的什么事,而重構可以幫助你把那些事做好

           

          3.1三次法則(The Rule of Three)

            Don Roberts 給了我一條準則:第一次做某件事時只管去做;第二次做類似的事會產生反感,但無論如何還是做了;第三次再做類似的事,你就應該重構。

            ☆ 事不過,則重構。(Three strikes and you refactor.

           

          3.2重構時機

            添加功能時一并重構

            修補錯誤時一并重構

            復審代碼時一并重構

           

          -以上章節摘抄自《重構-改善既有代碼的設計

           

          4.平臺重構案例

           

          4.1重構動機

            1. 實例模塊為View,重構元素為ViewAction、ViewProcessBean、View,以下為關系圖。

            

            2. 由于View存在多種editMode(編輯模式),而每個調用的地方都需要進行type code(類型碼)判斷,然后再進行相應的業務邏輯處理,最終在每個調用的地方都形成了大量的if-else代碼,大大減弱了代碼的可讀性,和邏輯清晰度。

           

            3. 調用的地方:

            

          4.2重構作法

            

           

          如上圖所示,將每種type code重構成subclass,加強了每種類型處理業務邏輯的能力。

           

          View-版本1566代碼片段:

           

          public EditMode getEditModeType() {
          if (EDIT_MODE_CODE_DQL.equals(getEditMode())) {
          return new DQLEditMode(this);
          }
          else if (EDIT_MODE_CODE_SQL.equals(getEditMode())) {
          return new SQLEditMode(this);
          }
          else if (EDIT_MODE_DESIGN.equals(getEditMode())) {
          return new DesignEditMode(this);
          }

          return new NullEditMode(this);
          }

          說明:調用者無需了解具體的類型,由View自身作判斷,返回EditMode接口,從而實現多態調用。

           

           

          ViewProcessBean代碼片段:

          重構前-版本1503:

           

          public String expDocToExcel(String viewid, WebUser user, ParamsTable params) throws Exception {
          if (view.getEditMode().equals(View.EDIT_MODE_DESIGN)) {
          datas
          = dp.queryBySQLPage(sql, params, tempPage, LINES, user.getDomainid());
          }
          else if (view.getEditMode().equals(View.EDIT_MODE_CODE_DQL)) {
          datas
          = dp.queryByDQLPage(dql, params, tempPage, LINES, user.getDomainid());
          }
          else if (view.getEditMode().endsWith(View.EDIT_MODE_CODE_SQL)) {
          datas
          = dp.queryBySQLPage(sql, params, tempPage, LINES, user.getDomainid());
          }
          }

           

          重構后-版本1566:

           

          public String expDocToExcel(String viewid, WebUser user, ParamsTable params) throws Exception {
          datas
          = view.getEditModeType().getDataPackage(params, tempPage, LINES, user, currdoc);
          //其他業務邏輯
          }

           

           

          5.結語

            由上述案例可看到,引入subclass代替type code可以大大減少if-else判斷,而且可以把責任內聚到每種type中,使代碼結構更清晰易懂。

           

          6.其他

                 在本案例中引入了空類型概念,即NullEditMode,代碼如下:

            

          /**
          *
          *
          @author nicholas zhen
          *
          */
          public class NullEditMode extends AbstractEditMode implements EditMode {

          public NullEditMode(View view) {
          super(view);
          }

          public String getQueryString(ParamsTable params, WebUser user, Document sDoc) {
          return "";
          }

          public DataPackage getDataPackage(ParamsTable params, WebUser user, Document doc) throws Exception {
          return new DataPackage();
          }

          public DataPackage getDataPackage(ParamsTable params, int page, int lines, WebUser user, Document doc) throws Exception {
          return new DataPackage();
          }

          public long count(ParamsTable params, WebUser user, Document doc) throws Exception {
          return 0;
          }
          }

          說明:空類型保證了調用每個方法都有默認值返回,而不需要進行非空判斷,當View沒有類型時,即返回默認的空類型

           

          原創人員:Nicholas


          文章來源:http://www.cnblogs.com/obpm/archive/2010/07/13/1776856.html
          posted on 2010-07-13 23:22 obpm 閱讀(231) 評論(0)  編輯  收藏 所屬分類: 架構設計
          主站蜘蛛池模板: 东明县| 乐陵市| 年辖:市辖区| 砀山县| 巨鹿县| 墨竹工卡县| 广宗县| 汶上县| 博兴县| 阳原县| 巴彦淖尔市| 新兴县| 靖江市| 宁晋县| 高陵县| 宿州市| 都江堰市| 星子县| 酉阳| 和平县| 漳州市| 攀枝花市| 望奎县| 九龙坡区| 清原| 广丰县| 信宜市| 陇西县| 西盟| 正蓝旗| 应用必备| 新田县| 洛阳市| 田东县| 崇阳县| 大足县| 福安市| 石楼县| 临潭县| 郴州市| 大同县|