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

1.2 理解標準化服務約定

每個服務都必須有公開化、標準化的服務,以使調用者可以遵循該約定。服務約定可以只是一個類,用于描述訪問者如何使用類的屬性和方法。在我們的應用程序里,使用接口來實現服務約定。接口在C#、VB.NET上都是可用的(事實上,幾乎所有的語言都支持接口),所以這不會對項目的語言選擇有任何限制。

服務約定是SOA的一個基本方面,它們允許調用代碼使用某服務所提供的功能,但不必直接引用該服務內完成該功能邏輯的類。這就是所謂的松耦合,我們在下一節中會詳細討論。

注意

在第4章,你將學習如何創建和使用服務,而無須直接引用它。這是我們使用的架構的關鍵部分。

接口

接口描述了實現類所提供的方法、屬性或者事件的抽象。接口不提供實現這些功能的邏輯(事實上,內含邏輯編碼的接口是不能夠被編譯的)。

1.創建接口

如代碼清單1.1所示,創建接口的語法與創建類的略有不同。

代碼清單1.1 創建接口


/// <summary>
/// Interfaces only describe the properties,
/// methods,and events that a class exposes for use.
/// Logic to implement these features is not allowed in
/// an interface.
/// </summary>
public interface IExample
{
  /// <summary>
  /// Example of a string property the implementing class
  /// must provide.
  /// </summary>
  string StringProperty { get; set; }
  /// <summary>
  /// Example of a read-only property.
  /// </summary>
  string ReadOnlyStringProperty { get; }
  /// <summary>
  /// Example of a method that accepts two parameters.
  /// </summary>
  int OperateOnTwoNumbers(int pNum1, int pNum2);
}

在這個例子中,該接口描述了兩個屬性和一個方法。任何想實現該接口的類必須提供這些屬性和方法。根據定義,只要是在接口中描述的內容,對調用代碼來說,都是可以使用的,所以public、private、internal、protected等權限修飾符不能用來限定接口。對于一個接口來說,真正的代碼只不過是一段關于實現類必須提供的內容的描述。另外,請注意接口名稱是以大寫字母"I"開頭,后面緊跟實現類的名稱。由于這種命名標準被廣泛采用,所以我們也這樣來命名接口。

2.實現接口

接口本身沒有多大用處,因為它不包含任何邏輯。我們需要創建一個類來實現接口中所描述的所有內容,如代碼清單1.2所示。

代碼清單1.2 實現接口


/// <summary>
/// An implementing class MUST provide the appropriate
/// items described in the interface or the project will not build.
/// The implementing class can add any additional
/// features deemed appropriate.
/// </summary>
public class Example : IExample
{
  /// <summary>
  /// Implement the StringProperty described in the interface.
  /// </summary>
  public string StringProperty { get; set; }
  /// <summary>
  /// The ReadOnlyStringProperty cannot have a public setter,
  /// but can have a private, protected, or internal setter.
  /// </summary>
  public string ReadOnlyStringProperty { get; internal set; }
  /// <summary>
  /// The implementing class must provide the method signatures
  /// described in the interface, though if no logic is
  /// added to the method, it will still build.
  /// </summary>
  public int OperateOnTwoNumbers(int pNum1, int pNum2)
  {
    return pNum1 + pNum2;
  }
  /// <summary>
  /// Any further customization of the implementing
  /// class is allowed.
  /// </summary>
  public bool MethodNotInTheInterface()
  {
    return true;
  }
}

如你在類的定義中所見,該類實現了代碼清單1.2中的接口。從一方面來說,如果一個類要想實現一個接口,那么它必須提供接口中描述的所有內容。如果實現類沒有實現接口定義中的部分內容,那么整個解決方案就不能成功生成。從另一方面來說,該類可以在不影響接口的前提下實現很多必要的附加屬性。這允許你增加任何附加的代碼以使該類實現其描述的內容。

一個類實現接口的唯一要求是必須實現該接口描述的所有內容的特征。只要方法存在即可,不必提供任何邏輯,因為接口沒有指明方法如何實現。

在代碼清單1.3所示的例子中,為了滿足需求,我們決定不實現OperationOnTwo Numbers方法,所以就簡單地拋出一個NotImplementedException異常。如果你認為實現類不需要定義一個方法,那么把此段代碼處理成拋出異常的做法要比在該段代碼處留空更加可取。通過拋出異常,在該方法被不正常地調用的情況下,我們肯定會接收到出錯信息。如果留空,那么該方法是否被調用將無從知曉,從而導致相對應的缺陷難以被發現。

代碼清單1.3 顯示方法不需要實現邏輯的例子


/// <summary>
/// Implementing a method described in an interface does not
/// require that proper logic be added, only that the method
/// signature is provided.
/// </summary>
public int OperateOnTwoNumbers(int pNum1, int pNum2)
{
  throw new NotImplementedException("OperateOnTwoNumbers");
}

3.使用接口

既然已經定義了接口和實現類,接下來看一下如何在業務邏輯中使用接口。代碼清單1.4中的例子展示了實現了一些業務邏輯的類如何使用接口和實現類。現在,我們簡單地用new關鍵字創建Example類。不久,我們將探索一種更好的、稱為“服務定位”的方法來創建這些類。

代碼清單1.4 使用接口


/// <summary>
/// This is an example of a class that uses the
/// interface we just created.
/// </summary>
public class BusinessLogic
{
  public int UseInterfaceImplementation()
  {
    //Though we are creating a real Example class, we
    //are assigning it to an IExample variable.
    IExample sampleClass = new Example();
    //We can use the variable reflecting the interface
    //as if it were the real class.
    return sampleClass.OperateOnTwoNumbers(1, 2);
  }
}

這里值得注意的是,雖然創建了具體的類Example,但是變量是定義為接口而不是類。這意味著涉及該變量的方法和屬性已在接口中定義了。如圖1.1所示,MethodNotInTheInterface方法不可用。

圖1.1 沒有在接口中定義的方法不可用

對于接口來說,它的一個極其強大和非常重要的特性是:不同的類可以同時實現一個接口。除了代碼清單1.2中的類,我們可以在同一個工程中另外聲明一個新的實現類。如代碼清單1.5所示,接口中各項的實現方式可以與第一個類完全不同,只要它們實現了接口固有的特征。

以上是使用接口的重要特征。后續篇章將會詳細介紹在服務中使用這些特征的原因。現在,你只需要接受并且堅信,對所有的服務都使用一個相關聯的接口是合理的,而且當你的代碼實現了接口后,使用起來將更靈活、更容易。

代碼清單1.5 接口的第二次實現


/// <summary>
/// This is a second implementation of the IExample interface.
/// It has no relation to the other implementation and can
/// implement completely different logic.
/// </summary>
public class AlternateExample : IExample
{
  /// <summary>
  /// The string property is the same as the previous implementation.
  /// </summary>
  public string StringProperty { get; set; }
  /// <summary>
  /// The ReadOnlyStringProperty will always return the
  /// given value.
  /// </summary>
  public string ReadOnlyStringProperty
  {
    get { return "I'm an Alternate"; }
  }
  /// <summary>
  /// This method operates on the two inputs in a different
  /// way, returning a completely different result than our
  /// previous implementation.
  /// </summary>
  public int OperateOnTwoNumbers(int pNum1, int pNum2)
  {
    return pNum1 * pNum2;
  }
}

主站蜘蛛池模板: 什邡市| 芒康县| 方城县| 石台县| 宜阳县| 鹰潭市| 怀仁县| 台州市| 广宗县| 吉林省| 岱山县| 赞皇县| 毕节市| 烟台市| 皋兰县| 呼图壁县| 元氏县| 汶上县| 长治市| 新郑市| 门源| 青田县| 北碚区| 崇州市| 武宣县| 汉川市| 台前县| 三亚市| 新邵县| 和田市| 华池县| 营山县| 舒城县| 伊春市| 伊宁市| 宁化县| 呼图壁县| 株洲县| 团风县| 陇西县| 青冈县|