天天看點

第一章 —— 簡單工廠模式(節選自:《大話設計模式》)

1.4 面向對象程式設計

  所有程式設計初學者碰到問題都會直覺地用計算機能夠了解的邏輯來描述和表達待解決的問題及具體的求解過程。這其實是用計算機的方式去思考,比如電腦這個程式:先要求輸入兩個數和運算符号,然後根據運算符号判斷選擇如何運算,得到結果,這本身沒有錯,但這樣的思維卻使得我們的程式隻為滿足實作目前的需求。

  這樣的程式不容易維護,不容易擴充,更不容易複用。進而達不到高品質代碼的要求。

1.5 活字印刷,面向對象

  曹操詩興大發,寫了一首詩:“喝酒唱歌,人生真爽……”,然後命印刷工匠刻版印刷以便流傳天下。

  樣張出來以後,曹操一看覺得過于俗氣,于是将“喝酒唱歌”改成了“對酒當歌”,于是就命工匠重新來過。工匠眼看連夜刻版之工徹底白費,心中叫苦不疊,但隻得照辦。

  樣張再次出來以後,曹操又覺得第二句寫的不好,于是将“人生真爽”改成了“人生幾何”,工匠得知後當即暈倒!

  三國時期,由于活字印刷術還未發明,是以要改字的時候,就必須要整個刻版全部重新刻。如果有了活字印刷,則隻需要改四個字即可,其餘工作都未白做,豈不妙哉:

    第一,要改,隻需更改要改之字,此為可維護;

    第二,這些字并非用完這次就無用,完全可以在後來的印刷中重複使用,此為可複用;

    第三,此詩若要加字,隻需另刻字加入即可,這是可擴充;

    第四,字的排列其實可能是豎排可能是橫排,此時隻需将活字移動就可做到滿足滿足排列需求,這就是靈活性好。

  而在活字印刷術出現之前,上面的四種特性都無法滿足,要修改,必須重刻,要加字,必須重刻,要重新排列,必須重刻,印完這本書後,此版已無任何可再利用價值。

1.6 面向對象的好處

  大鳥:“我以前也不懂,不過做了幾年軟體開發後,經曆了太多類似曹操這樣的客戶要改變需求、更改最初想法的事件,才逐漸明白當中的道理”。

  其實客觀地說,客戶的要求也并不過分,不就是改幾個字嗎,但面對已完成的程式代碼,卻是需要幾乎重頭來過的尴尬,這實在是痛苦不堪。

  說白了,原因就是因為我們原先所寫的程式,不容易維護,靈活性差,不容易擴充,更談不上複用,是以面對需求變化,加班加點,對程式動大手術的那種無奈也就成了非常正常的事了。

  之後當我學習了面向對象的分析設計程式設計思想,開始考慮通過封裝、繼承、多态吧程式的耦合度降低,傳統印刷術的問題就在于所有的字都刻在同一版面上造成耦合度太高所緻,開始用設計模式使得程式更加的靈活,容易修改,并且易于複用。這些都是面向對象帶來的好處。

1.7 複制 VS 複用

  有人說初級程式員的工作就是 Ctrl + C 和 Ctrl + V,這其實是非常不好的編碼習慣,因為當你的代碼中重複的代碼多到一定程度,維護的時候,可能就是一場災難。—— 越大的系統,這種方式帶來的問題越嚴重,程式設計有一原則,就是用盡可能的辦法去避免重複。

1.8 業務的封裝

  想想看,你寫的這段代碼,有哪些是和控制台無關的,而隻是和電腦有關的?

  小菜:“你的意思是分一個類出來?哦,對的,讓計算和顯示分開”。

  “準确地說,就是讓業務邏輯與界面邏輯分開,讓它們之間的耦合度下降。隻有分離開,才可以達到容易維護或擴充”。

  初級的面向對象代碼:

public class Operation
{
  public static double GetResult(double numberA, double numberB, string operate)
  {
    double result = 0d;
    switch (operate)
    {
      case "+":
        result = numberA + numberB;
        breake;
      case "-":
        result = numberA - numberB;
        breake;
      case "*":
        result = numberA * numberB;
        breake;
      case "/":
        result = numberA / numberB;
        breake;
    }
    return result;
  }
}      

    這種實作隻是簡單的利用了面向對象的封裝特性,而沒有使用面向對象的繼承和多态兩個特性。

1.9 進一步的實作(松耦合)

  operation 運算類:

   public class Operation
    {
        private double _numberA = 0;
        private double _numberB = 0;

        public double NumberA
        {
            get { return _numberA; }
            set { _numberA = value; }
        }
        public double NumberB
        {
            get { return _numberB; }
            set { _numberB = value; }
        }

        public virtual double GetResout()
        {
            double result = 0;
            return result;
        }
    }      

  加減乘除類:

/// <summary>
    /// 加法類,繼承運算類
    /// </summary>
    public class OperationAdd : Operation
    {
        public override double GetResout()
        {
            double result = 0;
            result = NumberA + NumberB;
            return result;
        }
    }

    /// <summary>
    /// 除法類,繼承運算類
    /// </summary>
    public class OperationDiv : Operation
    {
        public override double GetResout()
        {
            double result = 0;
            if (NumberB == 0)
                throw new Exception("除數不能為0。");
            result = NumberA / NumberB;
            return result;
        }
    }      

    這裡首先寫了一個運算類,它有兩個 Number 屬性,主要用于電腦的前後數,然後有一個虛方法 GetResult(),用于得到結果。

  然後我把加減乘除都寫成了運算類的子類,繼承它後重寫了 GetResult() 方法。—— 這樣(通過繼承)如果要修改任何一個算法,就不需要提供其他算法的代碼了。

1.10 簡單工廠模式

    現在就是如何執行個體化對象的問題了,這裡采用“簡單工廠模式”。

    到底執行個體化誰,将來會不會增加執行個體化的對象,比如增加開根運算,這是很容易變化的地方,應該考慮用一個單獨的類來做這個創造執行個體的過程,這就是工廠。

  簡單運算工廠類:

public class OperationFactory
    {
        public static Operation CreateOperate(string operate)
        {
            Operation oper = null;
            switch (operate)
            {
                case "+":
                    oper = new OperationAdd();
                    break;
                case "/":
                    oper = new OperationDiv();
                    break;
            }
            return oper;
        }
    }      

    這樣,隻需要輸入運算符号,工廠就可以執行個體化出合适的對象。

  用戶端代碼:

Operation oper;
            oper = OperationFactory.CreateOperate("+");
            oper.NumberA = 1;
            oper.NumberB = 2;
            double result = oper.GetResout();

            Console.WriteLine(result);
            Console.ReadLine();      

    程式設計是一門技術,更加是一門藝術,不能隻滿足于寫完代碼運作結果正确就完事,時常考慮如何讓代碼更加簡練,更加容易維護,容易擴充和複用,隻有這樣才可以真正得到提高。

轉載于:https://www.cnblogs.com/zhangchaoran/p/8336214.html

繼續閱讀