日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
軟件項目架構(gòu)簡明進(jìn)化史

1引言

曲陽網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、自適應(yīng)網(wǎng)站建設(shè)等網(wǎng)站項目制作,到程序開發(fā),運營維護(hù)。創(chuàng)新互聯(lián)2013年開創(chuàng)至今到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)。

  在標(biāo)題的取名上,不敢說頗費心機,也算得上花費了一點功夫的。首先想到的是“架構(gòu)設(shè)計過程”,又覺得是不是太大了,因為例子比較局部,不是很完整。叫做“結(jié)構(gòu)變化過程”可能更好點。但是又怕名字取的小氣了,進(jìn)來的人少,參與討論的就更少了,最終還是取了這個有點忽悠人的標(biāo)題“架構(gòu)演進(jìn)”。

  今天的這個架構(gòu)演進(jìn),使用系統(tǒng)中一個局部的實例進(jìn)行推導(dǎo)和演進(jìn),一起來觀察一下,架構(gòu)是如何不滿足需求的?架構(gòu)如何演進(jìn)?更好的架構(gòu)應(yīng)該具備哪些條件?有沒有更好的呢?

  業(yè)務(wù)場景

圖1 業(yè)務(wù)場景圖

  從上圖可以看出,就是一個電子商務(wù)網(wǎng)站常見的支付、支付的后續(xù)處理,這樣一個業(yè)務(wù)場景。支持多種支付方式,目前包括銀聯(lián)、支付寶,還有平臺賬戶。平臺賬戶就是注冊用戶將資金存儲在平臺為用戶建立并維護(hù)的一個賬戶里,購買平臺的產(chǎn)品,可以使用平臺賬戶中的資金進(jìn)行支付。

  2業(yè)務(wù)流程

  首先用戶選擇商品。

  下單,進(jìn)行支付。

  選擇支付方式。

  使用相應(yīng)支付方式進(jìn)行支付。第三方支付,會跳轉(zhuǎn)到第三方的支付頁面進(jìn)行支付。

  平臺進(jìn)行支付的后續(xù)處理,包括成功之后的修改狀態(tài)等,還包括失敗之后的記錄標(biāo)記等。

  第三方的支付,在打開第三方支付界面的時候,會告訴它一個平臺的回調(diào)地址,支付之后,通過回調(diào)地址接收第三方支付的結(jié)果,然后進(jìn)行后續(xù)處理。使用平臺賬戶支付,就直接進(jìn)行后續(xù)處理就可以了。

  當(dāng)然,這其中還會有一些細(xì)節(jié),不在我們的討論范圍。例如:使用平臺賬戶進(jìn)行支付,判斷賬戶金額是否充足。使用第三方支付,是否記錄第三方支付的完整過程,以及完整的支付流程。等等具體的業(yè)務(wù)細(xì)節(jié)均不在今天的討論范圍。

  3初級架構(gòu)-用存儲過程搞定它

  回調(diào)地址接收兩個參數(shù),一個是訂單編號,一個是標(biāo)志。標(biāo)志說明是成功還是失敗,或者是更加詳細(xì)的信息。

 
 
 
 
  1.   CREATE PROCEDURE Proc_PaymentHandle
  2.   @OrderSeqNo VARCHAR(36), --訂單編號
  3.   @ReturnCode VARCHAR(10), --返回狀態(tài)碼
  4.   @PaymentManner CHAR(1) --支付方式:1銀聯(lián),2支付寶,3平臺賬戶
  5.   AS
  6.   BEGIN
  7.   IF(@PaymentManner='1')
  8.   BEGIN
  9.   --更新訂單狀態(tài)
  10.   --更新銀聯(lián)支付信息
  11.   RETURN;
  12.   END
  13.   ELSE IF(@PaymentManner='2')
  14.   BEGIN
  15.   --更新訂單狀態(tài)
  16.   --更新支付寶支付信息
  17.   RETURN;
  18.   END
  19.   ELSE IF(@PaymentManner='3')
  20.   BEGIN
  21.   --更新定的狀態(tài)
  22.   --更新平臺賬戶支付信息
  23.   RETURN;
  24.   END
  25. END

  配合一段C#代碼,判斷一下支付方式,然后給存儲過程傳遞參數(shù)。這樣寫的話,上面的這個存儲過程很容易就超過1k行了,相信大家也寫過1k行以上的存儲過程,也維護(hù)過這樣的存儲過程,知道個中的酸甜苦辣。

  如果說那一天我們增加了一種支付方式,需要修改的地方包括哪些呢?

  界面要修改,存儲過程要打開修改,調(diào)用的C#代碼要修改。真是有點麻煩,最主要的是容易改錯了,誤改了不應(yīng)該動的地方才是最要命的。好吧,我們簡單分離一下。每種支付方式一個存儲過程,把對于支付方式的判斷放在代碼中,每種支付對應(yīng)一個代碼中的方法。這樣需要增加一種的話,只要改改支付方式判斷的代碼,然后重新寫一個存儲過程,重新寫一個方法調(diào)用一下新的存儲過程就可以了??墒沁€有一個問題,更新訂單狀態(tài)好像大家都在做,如果哪一些還需要加一些大家都需要做的事情呢?或者說修改一些大家都需要做的事情的細(xì)節(jié)?又或者說某兩個支付方式需要增加一個處理流程呢?打開存儲過程,狂修改吧?。。?!

  存儲過程有幾個不便利的地方:

  調(diào)試不方便

  測試不方便

  代碼不能折疊,多了之后要拖動滾動條才能找得到

  邏輯運算、大規(guī)模計算是存儲過程的弱項

  存儲過程的優(yōu)勢至少也有一個,就是修改之后,馬上可以見到效果。不用編譯。

  4中級架構(gòu)-在代碼中分離對每種信息的更新

  之前的架構(gòu)代碼中有很多的重復(fù)地方,例如:對于訂單信息的更新。如何把重復(fù)降低呢?降低重復(fù)也就集中了代碼,集中了將來也好維護(hù)。而且把它分離出來,獨立出來,好像更好點,在需要的地方調(diào)用就可以了。如果需要變更訂單的更新細(xì)節(jié),只要修改一下更新細(xì)節(jié)就可以了,不需要動支付的代碼。減小犯錯誤的概率。

  首先,將各種更新信息獨立出來。

 
 
 
 
  1.   public class OrderRepository2
  2.   {
  3.   public void UpdateState()
  4.   { throw new System.Exception(); }
  5.   }
  6.   public class PlatformAccountRepository2
  7.   {
  8.   public void Update()
  9.   { throw new System.Exception(); }
  10.   }
  11.   public class ZhifubaoRepository2
  12.   {
  13.   public void Update()
  14.   { throw new System.Exception(); }
  15.  }
  16.  public class YinlianRepository2
  17.   {
  18.   public void Update()
  19.   { throw new System.Exception(); }
  20.   }

  使用下面的方法進(jìn)行支付的后續(xù)處理。

 
 
 
 
  1.   public void HandlePaymentResult(PaymentManner2 paymentManner, string orderSeqNo)
  2.   {
  3.   switch (paymentManner)
  4.   {
  5.   case PaymentManner2.PlatformAccount :
  6.   var platformService = new PlatformAccountPaymentResultHandleService2();
  7.   platformService.Handle(orderSeqNo);
  8.   break;
  9.   case PaymentManner2.Yinlian :
  10.   var yinlianService = new YinlianPaymentResultHandleService2();
  11.   yinlianService.Handle(orderSeqNo);
  12.   break;
  13.   case PaymentManner2.Zhifubao :
  14.   var zhifubaoService = new ZhifubaoPaymentResultHandleService2();
  15.   zhifubaoService.Handle(orderSeqNo);
  16.   break;
  17.   }
  18.   } public enum PaymentManner2
  19.   {
  20.   Zhifubao,
  21.   Yinlian,
  22.   PlatformAccount
  23.   }
  24.   public class ZhifubaoPaymentResultHandleService2
  25.   {
  26.   private OrderRepository2 _orderManagement;
  27.   private ZhifubaoRepository2 _zhifubaoManagement;
  28.   public void Handle(string orderSeqNo)
  29.   {
  30.   using (TransactionScope scope = new TransactionScope())
  31.   {
  32.   _orderManagement.UpdateState();
  33.   this._zhifubaoManagement.Update();
  34.   scope.Complete();
  35.   }
  36.   }
  37.   }
  38.   public class YinlianPaymentResultHandleService2
  39.   {
  40.   private OrderRepository2 _orderManagement;
  41.   private YinlianRepository2 _yinlianManagement;
  42.   public void Handle(string orderSeqNo)
  43.   {
  44.   using (TransactionScope scope = new TransactionScope())
  45.   {
  46.   this._orderManagement.UpdateState();
  47.   this._yinlianManagement.Update();
  48.   scope.Complete();
  49.   }
  50.   }
  51.   }
  52.   public class PlatformAccountPaymentResultHandleService2
  53.   {
  54.   private OrderRepository2 _orderManagement;
  55.   private PlatformAccountRepository2 _platformAccountManagement;
  56.   public void Handle(string orderSeqNo)
  57.   {
  58.   using (TransactionScope scope = new TransactionScope())
  59.   {
  60.   this._orderManagement.UpdateState();
  61.   this._platformAccountManagement.Update();
  62.   scope.Complete();
  63.   }
  64.   }
  65.   }

  增加支付方式的話,新建一個HandleService類,寫一些處理代碼,然后在public void HandlePaymentResult(PaymentManner2 paymentManner, string orderSeqNo)方法的switch中增加一個case就可以了。

  但是頁面的可選支付方式還是寫死了,沒有動態(tài)的變化,支付方式是否可以動態(tài)配置呢?而且可以方便的測試呢?例如:雖然我還沒有銀聯(lián)的接口,但是我想測試一些,銀聯(lián)支付之后平臺的處理是否正確,該更新的信息是否都更新了呢?沒有銀聯(lián)的接口,是不是就不能做了呢?有沒有辦法解決呢?

  答案是:有。

  還有就是上面的switch。。。case,好像會很長,也很丑,這個地方能否改進(jìn)呢?很多人在學(xué)習(xí)了重構(gòu)之后,會提出很多的方法來解決這個問題,我們再后面也一塊來解決一下。

  5高級架構(gòu)-少用存儲過程處理業(yè)務(wù)的靈活架構(gòu)

  我們的高級架構(gòu)有幾個目標(biāo)

  減少存儲過程中的業(yè)務(wù)邏輯,讓存儲過程更加純粹的做事,做它擅長的事情。

  可以靈活的增加或者減少支付方式。達(dá)到在增加或者減少支付方式的時候,盡量少的修改代碼,盡量減少依賴。減少支付對于支付方式的依賴,支付方式對于后續(xù)處理的依賴。

  代碼結(jié)構(gòu)更加清晰。

  為了達(dá)到上面的幾個目標(biāo),計劃獨立幾個部分。

  支付方式的管理。

  每一種支付方式的處理過程。這個在中級架構(gòu)里面已經(jīng)做的差不多了,這里會做的更好一點,抽象這個支付處理過程。

  還有就是要隱藏支付方式和具體的支付方式處理過程映射代碼。具體的支付方式指的是:銀聯(lián)或者是支付寶這種具體的一種支付方式。目的就是讓對于支付訂單的處理獨立化,固定化,支持變化。

  5.1支付方式的管理

 
 
 
 
  1.   public enum PaymentManner1{
  2.   Zhifubao,
  3.   Yinlian,
  4.   PlatformAccount
  5.   }
  6.   public class PaymentMannerParams
  7.   {
  8.   /// 
  9.   /// 地址還是內(nèi)部方法
  10.   /// 
  11.   public UriOrFunction UriOrFunction { get; set; }
  12.   /// 
  13.   /// 地址
  14.   /// 
  15.   public string Uri { get; set; }
  16.   /// 
  17.   /// 方法名
  18.   /// 
  19.   public string FunctionName { get; set; }
  20.   enum UriOrFunction
  21.   {
  22.   Uri,
  23.   Function
  24.   }
  25.   }
  26.   public class PaymentMannerManagement1
  27.  {
  28.   public DictionaryFindAvailableManner(decimal moneyOfPay)
  29.   {
  30.   throw new System.Exception();
  31.   }
  32.   }

  通過FindAvailableManner方法獲取支付方式。每種支付方式PaymentManner,都帶有一個參數(shù)實體PaymentMannerParams,里面的UriOrFunction來決定是通過網(wǎng)頁還是內(nèi)部方法來支付,Uri就跳轉(zhuǎn)到Uri就可以了,F(xiàn)unction就調(diào)用FunctionName中的方法就可以了。支付的時候用下面的Pay先獲取支付方式信息,然后根據(jù)每種支付方式的參數(shù)來決定具體的支付。

 
 
 
 
  1.   public class OrderManagement1
  2.   {
  3.   public void Pay(decimal money)
  4.   {
  5.   var manner= new PaymentMannerManagement1().FindAvailableManner(money);
  6.   //后續(xù)支付
  7.   }
  8.   }

  之前說的,如果銀聯(lián)還沒有接口,或者接口暫時不能用了,想測試一下后續(xù)的處理,就可以將銀聯(lián)這種Manner的UriOrFunction設(shè)置為Function,現(xiàn)用內(nèi)部的方法來測試后續(xù)的處理是否正確。等可以用的時候,在變更為Uri就可以了。

  5.2支付過程的抽象

  通過建立支付處理的接口,將支付處理的代碼抽象成下面的樣子。

 
 
 
 
  1.   public class Service1
  2.   {
  3.   public void HandlePaymentResult(PaymentManner1 paymentManner,string orderSeqNo)
  4.   {
  5.   IPaymentResultHandleService1 handleService = PaymentResultHandleServiceFactory1.GetService(paymentManner);
  6.   handleService.Handle(orderSeqNo);
  7.   }
  8.   }

  這個處理的代碼,原則來說以后都不需要修改了。后面要做的就是定義一種新的支付方式枚舉量,然后實現(xiàn)IPaymentResultHandleService1 接口,寫一些處理的代碼就可以了。

  5.3完整代碼using System;

 
 
 
 
  1.   using System.Collections.Generic;
  2.   using System.Linq;
  3.   using System.Text;
  4.   using System.Transactions;
  5.   namespace ConsoleApplication1
  6.  {
  7.   public class Service1
  8.   {
  9.   public void HandlePaymentResult(PaymentManner1 paymentManner,string orderSeqNo)
  10.   {
  11.   IPaymentResultHandleService1 handleService = PaymentResultHandleServiceFactory1.GetService(paymentManner);
  12.   handleService.Handle(orderSeqNo);
  13.   }
  14.   }
  15.   public class OrderManagement1
  16.   {
  17.   public void Pay(decimal money)
  18.   {
  19.   var manner= new PaymentMannerManagement1().FindAvailableManner(money);
  20.   //后續(xù)支付
  21.   }
  22.   }
  23.   public enum PaymentManner1
  24.   {
  25.   Zhifubao,
  26.   Yinlian,
  27.   PlatformAccount
  28.   }
  29.   public class PaymentMannerParams
  30.   {
  31.   /// 
  32.   /// 地址還是內(nèi)部方法
  33.   /// 
  34.   public UriOrFunction UriOrFunction { get; set; }
  35.   /// 
  36.   /// 地址
  37.   /// 
  38.   public string Uri { get; set; }
  39.   /// 
  40.   /// 方法名
  41.   /// 
  42.   public string FunctionName { get; set; }
  43.   enum UriOrFunction
  44.   {
  45.   Uri,
  46.   Function
  47.   }
  48.   }
  49.   public class PaymentMannerManagement1
  50.   {
  51.   public DictionaryFindAvailableManner(decimal moneyOfPay)
  52.   {
  53.   throw new System.Exception();
  54.   }
  55.   }
  56.   public class PaymentResultHandleServiceFactory1
  57.   {
  58.   private static PaymentResultHandleServiceFactory1()
  59.   {
  60.   _serviceMap = new Dictionary();
  61.   _serviceMap.Add(PaymentManner1.PlatformAccount, new PlatformAccountPaymentResultHandleService1());
  62.   _serviceMap.Add(PaymentManner1.Yinlian, new YinlianPaymentResultHandleService1());
  63.   _serviceMap.Add(PaymentManner1.Zhifubao,new ZhifubaoPaymentResultHandleService1());
  64.   }
  65.   private static Dictionary _serviceMap;
  66.   public static IPaymentResultHandleService1 GetService(PaymentManner1 paymentManner )
  67.   {
  68.   return _serviceMap[paymentManner];
  69.   }
  70.   }
  71.   public interface IPaymentResultHandleService1
  72.   {
  73.   void Handle(string orderSeqNo);
  74.   }
  75.   public class ZhifubaoPaymentResultHandleService1:IPaymentResultHandleService1
  76.   {
  77.   private OrderRepository1 _orderManagement;
  78.   private ZhifubaoRepository1 _zhifubaoManagement;
  79.   public void Handle(string orderSeqNo)
  80.   {
  81.   using (TransactionScope scope = new TransactionScope())
  82.   {
  83.   _orderManagement.UpdateState();
  84.  this._zhifubaoManagement.Update();
  85.  scope.Complete();
  86.   }
  87.   }
  88.   }
  89.   public class YinlianPaymentResultHandleService1 : IPaymentResultHandleService1
  90.  {
  91.   private OrderRepository1 _orderManagement;
  92.   private YinlianRepository1 _yinlianManagement;
  93.   public void Handle(string orderSeqNo)
  94.   {
  95.   using (TransactionScope scope = new TransactionScope())
  96.   {
  97.   this._orderManagement.UpdateState();
  98.   this._yinlianManagement.Update();
  99.   scope.Complete();
  100.   }
  101.   }
  102.   }
  103.   public class PlatformAccountPaymentResultHandleService1:IPaymentResultHandleService1
  104.   {
  105.   private OrderRepository1 _orderManagement;
  106.   private PlatformAccountRepository1 _platformAccountManagement;
  107.   public void Handle(string orderSeqNo)
  108.   {
  109.   using (TransactionScope scope = new TransactionScope())
  110.   {
  111.   this._orderManagement.UpdateState();
  112.   this._platformAccountManagement.Update();
  113.   scope.Complete();
  114.   }
  115.   }
  116.   }
  117.   public class OrderRepository1
  118.   {
  119.   public void UpdateState()
  120.   { throw new System.Exception(); }
  121.   }
  122.   public class PlatformAccountRepository1
  123.   {
  124.   public void Update()
  125.  { throw new System.Exception(); }
  126.  }
  127.   public class ZhifubaoRepository1
  128.   {
  129.  public void Update()
  130.  { throw new System.Exception(); }
  131.   }
  132.   public class YinlianRepository1
  133.   {
  134.   public void Update()
  135.   { throw new System.Exception(); }
  136.   }
  137.   }

  6總結(jié)

  類的依賴最好使用抽象,避免具體類的直接引用。

  盡量不要再存儲過程中處理業(yè)務(wù),在系統(tǒng)越做越大,你會越來越贊同我的說法。原因至少兩點:1維護(hù)累死人,2數(shù)據(jù)庫不擅長數(shù)值計算和處理。

  職責(zé)單一,功能獨立,代碼分離。


文章名稱:軟件項目架構(gòu)簡明進(jìn)化史
標(biāo)題鏈接:http://www.5511xx.com/article/copooji.html