邁向架構設計師之路系列—簡單對象訪問模式(一)

來源:互聯網
上載者:User

  假設情境

  現在假如公司要你做一個公司內部的薪資管理系統,根據職位的不同,每月的工資自然不一樣,經理一月10000加上分紅1000,技術人員一月5000加上200的餐補,客服一月3000,現在要是由你來做,你會怎麼設計?代碼無錯便是優已經不適用了

  閱讀目錄

  一:大部分人的寫法v1.0

  二:第一次改版後的代碼v1.1

  三:第二次改版後的代碼v1.2

  四:第三次改版後的代碼v1.3

  五:UML類圖解析

  六:總結

  七:思考

  一:大部分人的寫法v1.0

  這樣的寫法會帶來一個問題?什麼問題呢?複用性的問題

  假如現在你接了個私活,別的公司讓你也寫個公司內部的薪資計算系統,你說那還不簡單,把代碼複製過去就行啊,有人說過初級程式員的工作就是Ctrl+C和Ctrl+V,這其實是非常不好的編碼習慣,因為當你的代碼中重複的代碼多到一定程度的時候,維護起來就是一場災難,越大的系統這種方式帶來的問題越嚴重,編程有一個原則就是儘可能的想辦法避免重複,再說了比如客戶要求你給它們公司做的內部薪資計算系統是個Web版的,或者是個WindowsApplication版的,那麼你下面的代碼就廢掉了,想想看,薪資計算系統哪些是和控制台程式無關的,只和計算有關的,也就是說分出一個類讓計算和顯示分開,也就是要讓業務和介面分開

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;

  namespace _1_SimpleFactory
  {
      class Program
      {
          static void Main(string[] args)
          {
                try
                {
                    int intSalary = 0; ;//薪水
                    string strPost = Console.ReadLine();//職位
                    switch (strPost)
                    { 
                        case "經理":
                            intSalary = 10000 + 1000;
                           break;
                        case "技術":
                            intSalary = 5000 + 200;
                           break;
                        case "客服":
                            intSalary = 3000;
                           break;
                    }
                    Console.WriteLine("工資是:" + intSalary);
                    Console.ReadLine();
                 }
                  catch (Exception ex)
                 { 
                 }
          }
      }
  }

  

   二:第一次改版後的代碼v1.1

  為什麼要改版?因為考慮到複用性的問題

  要讓商務邏輯和介面邏輯分開,讓它們的耦合度下降,只有分離開才能達到更容易維護和擴充,也就是業務的封裝

  我們建立一個類庫,名字叫BusinessLogic,裡面有個類檔案叫Calculate.cs,專門處理根據職位計算工資的,當我們需要做個Web版的話,只需要把介面邏輯檔案Program.cs代碼中的“Console.WriteLine("工資是:" + intSalary);Console.ReadLine();”換成“ASP.NET的Response.Write(("工資是:" + intSalary);Response.End();”就OK了,商務邏輯檔案Calculate.cs是可以複用的,這樣就達到了業務和介面分離了,如果你現在要做一個Windows版的,手機版的,PDA版的,都可以複用這個Calculate類

  這次改版後的代碼修複了原始代碼不能複用性的問題,這裡只是用到了物件導向三個特性中的封裝特性,把商務邏輯封裝起來,繼承和多態在這裡還沒用到呢

  這樣的寫法又會帶來一個新的問題?缺乏靈活性,靈活性包含兩個方面,一個方面是修改性,一個方面則是擴充性

  已經把業務和介面分離了不是很靈活了嗎?好那我們現在打個比方,比方CEO現在要在公司中安排一些親戚進來工作,職位給了個虛頭銜是助理,親戚自然不能虧待,工資是每月6000+1000,你該怎麼設計呢?只要修改Calculate.cs 商務邏輯檔案,在裡面加個分支就行了,問題來了,如果你這樣做,你只是要增加一個職位卻讓“經理”和“技術”以及“客服”參加了編譯,這是糟糕的,你萬一一不小心把case "經理":intSalary = 10000 + 1000;改成了case "經理":intSalary = 1000 + 1000;你們經理該弄死你了,其次你看到“經理”補助1000,我們技術部補助才200,他奶奶的,不行我要提高我們部門的待遇,然後你把case "技術":intSalary = 5000 + 200;改寫成intSalary = 5000 + 800;這樣你們部門每個技術都要比原來多發600元人民幣了,本來是讓你增加一個功能,卻讓原來運行良好的代碼產生了變化,這是非常糟糕的且有巨大風險的,那麼我們下面該怎麼設計呢?

   1:Calculate.cs 商務邏輯檔案

   using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;

  namespace BusinessLogic
  {
      public class Calculate
      {
          /// <summary>
          /// 計算工資
          /// </summary>
          /// <param name="strPost">職位描述</param>

      ///<returns>工資</returns>
          public static int CalculateSalary(string strPost)
          {
              int intSalary = 0; ;//薪水
              switch (strPost)
              {
                  case "經理":
                      intSalary = 10000 + 1000;
                     break;
                  case "技術":
                      intSalary = 5000 + 200;
                     break;
                  case "客服":
                      intSalary = 3000;
                     break;
              }
              return intSalary;
          }
      }
  }

  2:Program.cs 介面邏輯檔案

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using BusinessLogic;

  namespace _1_SimpleFactory
  {
      class Program
      {
          static void Main(string[] args)
          {
              try
              {
                  int intSalary = Calculate.CalculateSalary(Console.ReadLine());
                  Console.WriteLine("工資是:" + intSalary);
                  Console.ReadLine();
              }
              catch (Exception ex)
              { 
                
              }
          }
      }
  }

  工程架構圖

  

  三:第二次改版後的代碼v1.2

  為什麼要再次改版呢?因為考慮到靈活性的問題

  我們要讓“經理”和“技術”以及“客服”運算類分開,修改其中一個類不影響其他的類,增加“助理”等運算類也不影響其他的代碼

  首先還是在名字叫BusinessLogic的類庫裡面有個類檔案叫Calculate.cs的計算工資類,裡面有個虛方法CalculateSalary(),用於計算工資的,然後我們把“經理”和“技術”及“客服”和“助理”寫成了計算工資類的子類,繼承後,重寫了CalculateSalary()方法,這樣要修改任何一個職位的工資,就不需要提供其他職位的代碼了,其次要增加一個職位,只需要建立一個類繼承計算工資類,重寫CalculateSalary()方法就行了,也不用提供其他職位的代碼了

  這次改版後的代碼修複了第一版代碼不具有靈活性的問題

  這樣寫又會帶來一個新的問題?什麼問題呢?就是如何讓用戶端知道我想用哪個計算工資類呢?我們是用CalculateJinLi.cs這個經理計算工資類,還是用CalculateJiShu.cs這個技術計算工資類呢?

  1:Calculate.cs

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;

  namespace BusinessLogic
  {
      /// <summary>
      /// 計算工資抽象類別,這個抽象不是指把它定義為抽象類別,而是它存在的意義是為了抽象
      /// </summary>
      public class Calculate
      {
          /// <summary>
          /// 計算工資
          /// </summary>
          ///<returns>工資</returns>
          public virtual int CalculateSalary()
          {
              int intSalary = 0; ;//薪水
              return intSalary;
          }
      }
  }

  2:CalculateJinLi.cs

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;

  namespace BusinessLogic
  {
      /// <summary>
      /// 計算經理工資的類,繼承計算工資類
      /// </summary>
      public class CalculateJinLi:Calculate
      {
          public override int CalculateSalary()
          {
              int intSalary = 10000 + 1000 ;//薪水
              return intSalary;
          }
      }
  }

  3:CalculateJiShu.cs

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;

  namespace BusinessLogic
  {  
      /// <summary>
      /// 計算技術工資的類,繼承計算工資類
      /// </summary>
      public class CalculateJiShu:Calculate
      {
          public override int CalculateSalary()
          {
              int intSalary = 5000 + 200;
              return intSalary;
          }
      }
  }

  4:CalculateKeFu.cs

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;

  namespace BusinessLogic
  {
      /// <summary>
      /// 計算客服工資的類,繼承計算工資類
      /// </summary>
      public class CalculateKeFu:Calculate
      {
          public override int CalculateSalary()
          {
              int intSalary = 3000;
              return intSalary;
          }
      }
  }

  5:CalculateZhuLi.cs

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;

  namespace BusinessLogic
  {
      /// <summary>
      /// 計算助理工資的類,繼承計算工資類
      /// </summary>
      public class CalculateZhuLi:Calculate
      {
          public override int CalculateSalary()
          {
              int intSalary = 6000 + 1000;
              return intSalary;
          }
      }
  }

  工程架構圖

  

   四:第三次改版後的代碼v1.3

   第二次代碼改版後遇到的問題就是如何去執行個體化對象的問題,到底要執行個體化誰,將來會不會增加執行個體化的對象,比如增加“助理”職位的計算工資,這是很容易變化的地方,以後保不準會增加“銷售”這個職位的計算工資類等,應該考慮一個單獨的類來做這個創造執行個體的過程,這就是工廠

  在第二版代碼上,我們增加CalculateFactory這個類庫,裡面有個CalculateFactory.cs類檔案,類檔案中有個CreateCalculate()方法,根據輸入的職位,工廠執行個體化出合適的對象,通過多態返回父類的方式實現計算工資的結果

  1:CalculateFactory.cs 工廠類檔案

  using System.Linq;
  using System.Text;
  using BusinessLogic;

  namespace CalculateFactory
  {  
      /// <summary>
      /// 計算工資工廠類
      /// </summary>
      public class CalculateFactory
      {
          /// <summary>
          /// 根據傳入的職位創造對應的執行個體
          /// </summary>
          /// <param name="strPost">職位</param>
          /// <returns>Calculate抽象類別</returns>
          public static Calculate CreateCalculate(string strPost)
          {
              Calculate calulate = null;
              switch (strPost)
              { 
                  case "經理":
                      calulate = new CalculateJinLi();
                      break;
                  case "技術":
                      calulate = new CalculateJiShu();
                      break;
                  case "客服":
                      calulate = new CalculateKeFu();
                      break;
                  case "助理":
                      calulate = new CalculateZhuLi();
                      break;
              }
              return calulate;
          }
      }
  }

  2:Program.cs 用戶端檔案

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using BusinessLogic;
  using CalculateFactory;

  namespace _1_SimpleFactory
  {
      class Program
      {
          static void Main(string[] args)
          {
              Calculate calculate = null;
              //由工廠根據參數決定要執行個體化哪個對象
              calculate = CalculateFactory.CalculateFactory.CreateCalculate("經理");
              int intResult = calculate.CalculateSalary();
              Console.WriteLine("經理工資為:" + intResult);
              calculate = CalculateFactory.CalculateFactory.CreateCalculate("技術");
              intResult = calculate.CalculateSalary();
              Console.WriteLine("技術工資為:" + intResult);
              calculate = CalculateFactory.CalculateFactory.CreateCalculate("客服");
              intResult = calculate.CalculateSalary();
              Console.WriteLine("客服工資為:" + intResult);
              calculate = CalculateFactory.CalculateFactory.CreateCalculate("助理");
              intResult = calculate.CalculateSalary();
              Console.WriteLine("助理工資為:" + intResult);
              Console.ReadLine();
          }
      }
  }

  運行

  

  工程架構圖

  

   五:UML類圖解析

  整合模組化語言UML(是Unified Modeling Language)的縮寫,是用來對軟體密集系統進行可視化建模的一種語言,UML為物件導向開發系統的產品進行說明,可視化,和編製文檔的一種標準語言

  類圖分為三層,第一層顯示類的名稱,如果是抽象類別,則用斜體表示,第二層是類的特性,通常是欄位和屬性,第三層是類的操作,通常是方法和行為,前面的符號“+”,表示public,”-“表示private,“#”表示protected

  

  六:總結

  這樣我們就完成了一個具有複用性,靈活性(可修改,可擴充)的公司內部薪資管理系統,我們同時也看到這樣一個小小的公司內部薪資系統,都用到了封裝,繼承,多態

  七:思考

  如果我們有一天我們需要更改經理的工資怎麼辦?我們只需要改CalculateJinLi.cs裡的代碼就行了,如果我們需要增加“銷售”職位的工資演算法怎麼辦?我們只需要增加相應的子類就行了,還要去計算工資工廠在switch裡增加分支就行了,那我們要去修改介面怎麼辦?比如我們換成Web版的,那就去改介面呀,跟運算毫無關係

  這個只是24種設計模式中最簡單的“簡單對象訪問模式”,其他很多設計模式有的很複雜,由於平時工作很忙,沒有及時更新請大家諒解,請關注我的部落格

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.