官术网_书友最值得收藏!

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)信息由服務的目的決定。

主站蜘蛛池模板: 安福县| 唐河县| 百色市| 汝阳县| 丹寨县| 海门市| 广东省| 乌兰浩特市| 靖边县| 松江区| 京山县| 治多县| 富川| 文水县| 金湖县| 宝丰县| 洛阳市| 胶南市| 九寨沟县| 安福县| 四会市| 洛扎县| 科尔| 灵石县| 潜山县| 平陆县| 天峨县| 泰兴市| 皮山县| 阆中市| 茌平县| 三河市| 昌平区| 会东县| 丹棱县| 湖北省| 综艺| 雷山县| 泰顺县| 大埔区| 孝感市|