- 軟件再工程:優(yōu)化現(xiàn)有軟件系統(tǒng)的方法與最佳實踐
- (美)Bradley Irby
- 1499字
- 2020-11-04 16:44:58
1.7 理解服務的無狀態(tài)性
無狀態(tài)(statelessness)指的是服務內(nèi)部變量值的存儲。如果一個服務的確無狀態(tài),那么就能調(diào)用服務的任何方法或引用該服務的任何屬性,而且只要傳遞相同的參數(shù),該服務就能以相同的方式正常運行。換言之,服務中存儲的值可以被外部調(diào)用者改變,而且不會影響操作的結(jié)果。
為了了解無狀態(tài)性,回顧一下代碼清單1.10。它展示了一個在商店買東西的過程的服務。
代碼清單1.10 不能退貨的購物過程示例
/// <summary> /// Class representing the process of buying an item /// from a store. /// </summary> public class SalesclerkNoRefunds { /// <summary> /// Method to call when a customer is buying an item. /// </summary> public void SellItem(string itemToSell, string nameOfPurchaser) { var price = GetItemPrice(itemToSell); GetPaymentFromCustomer(price); } /// <summary> /// Interacts with the customer to get payment. /// </summary> private void GetPaymentFromCustomer(double amount) { //Get the payment from the customer } /// <summary> /// Lookup the price of the item and return it /// </summary> private double GetItemPrice(string itemToSell) { //Lookup the price of the item and return it. return 15.00; } }
在這個銷售過程中,我們可以從商店中的任何一個選定的職員處購買東西,而且可以順利地完成此次購買。該服務沒有局部變量和狀態(tài),所以任何一個售貨員都能處理這個業(yè)務。然而,這個過程不允許退貨,它僅僅支持購物。讓我們來完善這個類,為這個類增加一個退貨的方法。思考代碼清單1.11所示的已經(jīng)優(yōu)化了的類和ReturnItem方法。
代碼清單1.11 允許退貨的購物過程示例
/// <summary> /// Class representing the process of buying an item. /// </summary> public class SalesclerkWithState { private List<Purchase> _rememberedPurchases; public SalesclerkWithState() { _rememberedPurchases = new List<Purchase>(); } /// <summary> /// Method to call when a customer is buying an item. /// </summary> public void SellItem(string itemToSell, string nameOfPurchaser) { var purchase = new Purchase(); purchase.PurchaserName = nameOfPurchaser; purchase.SaleDate = DateTime.Today; purchase.ItemSold = itemToSell; purchase.AmountPaid= GetItemPrice(itemToSell); ReceiveOrRefundPayment(purchase.AmountPaid); _rememberedPurchases.Add(purchase); } /// <summary> /// Method to call when the customer is returning the item. /// </summary> public void ReturnItem() { var purchase = RememberItemSoldToCustomer(); ReceiveOrRefundPayment(-purchase.AmountPaid); } /// <summary> /// Charge the customer credit card for the purchase. /// </summary> private Purchase RememberItemSoldToCustomer() { //Recall the customer and how much they paid. return _rememberedPurchases[0]; } /// <summary> /// Interacts with the customer to get the credit card number. /// </summary> private void ReceiveOrRefundPayment(double amount) { //Get the payment from the customer } /// <summary> /// Lookup the price of the item and return it. /// </summary> private double GetItemPrice(string itemToSell) { //Lookup the price of the item and return it. return 154.00; } private class Purchase { public string PurchaserName { get; set; } public double AmountPaid { get; set; } public DateTime SaleDate { get; set; } public string ItemSold { get; set; } } }
該類引入了ReturnItem方法,但需注意的是也在服務中引入了狀態(tài)。為了允許消費者退貨,售貨員必須知道消費者為商品支付了多少錢。如果不這么做,有些人可以將大減價期間買的商品在減價結(jié)束后以原價退回給商店。因此,售貨員需要記得每個購物的人以多少價格購買了什么商品。為了追蹤這些信息,我們引入了Purchase類和購物清單。
現(xiàn)在我們可以在同一家商店購物和退貨。然而,使用現(xiàn)有的設(shè)計,我們必須和最初賣那個商品的售貨員進行溝通。注意,Purchase類是私有的,代表它僅由最初的那個售貨員通過回憶獲取。如果換一個售貨員,他將不能記起那次購買,也就不能退款。這是在服務中引入狀態(tài)的弊端。我們不能實例化Salesclerk類的兩個副本,而且也不能在兩個副本之間隨意返回一些東西,必須找到最初賣給我們商品的店員。
到目前為止,構(gòu)建服務只有以下兩種選擇。
● 無狀態(tài),但是不包含我們想要的所有功能;
● 引入帶有狀態(tài)的應用程序,并面對隨之而來的問題。
我們不得不存儲系統(tǒng)的狀態(tài),但是可以把狀態(tài)存儲在系統(tǒng)外部,并在需要時回傳給服務,以解決這個問題。如代碼清單1.12所示,我們考慮的是無狀態(tài)版本的包含退款的銷售過程。
代碼清單1.12 允許退貨的無狀態(tài)購物過程示例
/// <summary> /// Class representing the process of buying a shirt. /// </summary> public class SalesClerkWithNoState { /// <summary> /// Method to call when a customer is buying an item. /// </summary> public SalesReceipt SellItem(string itemToSell) { var receipt = new SalesReceipt(); receipt.SaleDate = DateTime.Today; receipt.ItemSold = itemToSell; receipt.AmountPaid= GetItemPrice(itemToSell); ReceiveorRefundPayment(receipt.AmountPaid); return receipt; } /// <summary> /// Method to call when the customer is returning the item. /// </summary> public void ReturnItem(SalesReceipt receipt) { GetReceiptAndItemFromCustomer(); ReceiveorRefundPayment(-receipt.AmountPaid); } /// <summary> /// Get the necessary items from the customer. /// </summary> private void GetReceiptAndItemFromCustomer() { //receive the item and receipt from customer } /// <summary> /// Interacts with the customer to get the credit card number. /// </summary> private void ReceiveorRefundPayment(double amount) { //Get the payment from the customer } /// <summary> /// Lookup the price of the item and return it. /// </summary> private double GetItemPrice(string itemToSell) { //lookup the price of the item and return it return 154.00; } } /// <summary> /// Reflects information about the purchase. /// </summary> public class SalesReceipt { public double AmountPaid { get; set; } public DateTime SaleDate { get; set; } public string ItemSold { get; set; } }
在這個類中,我們引入了SalesReceipt類并刪除了Purchase類。我們設(shè)置SalesReceipt類為public,并刪除了私有的、用于記錄所有商品的購物清單。
通過引入收據(jù)的公共認知的概念,我們把存儲系統(tǒng)狀態(tài)的工作轉(zhuǎn)交給外部調(diào)用者,使得SalesClerkWithNoState符合無狀態(tài)的要求。有了收據(jù),我們可以找任何一位售貨員退貨,這使得交易更容易完成,服務更有用。
我們盡可能把服務設(shè)置為無狀態(tài)的,但是很多情況下,在服務中保留一些狀態(tài)信息是有必要的。需要保留多少狀態(tài)信息由服務的目的決定。
- 區(qū)塊鏈架構(gòu)與實現(xiàn):Cosmos詳解
- Python算法從菜鳥到達人
- MongoDB,Express,Angular,and Node.js Fundamentals
- NetBeans IDE 8 Cookbook
- Regression Analysis with Python
- Beginning C++ Game Programming
- 跟戴銘學iOS編程:理順核心知識點
- Mastering Drupal 8
- Implementing Domain:Specific Languages with Xtext and Xtend
- Tkinter GUI Programming by Example
- 打造流暢的Android App
- Visual FoxPro數(shù)據(jù)庫程序設(shè)計
- C/C++語言程序開發(fā)參考手冊
- 從零開始:Qt可視化程序設(shè)計基礎(chǔ)教程
- HTML5+CSS3從入門到精通(微課精編版)