WCF從理論到實踐(17):OO大背離(帶視頻+ppt+源碼)

作者: jillzhang  來源: 博客園  發布時間: 2008-11-28 16:03  閱讀: 2888 次  推薦: 1   原文鏈接   [收藏]  

系列文章導航:

WCF從理論到實踐(1):揭開神秘面紗

WCF從理論到實踐(2):決戰紫禁之巔

WCF從理論到實踐(3):八號當鋪之黑色契約

WCF從理論到實踐(4):路在何方

WCF從理論到實踐(5):Binding細解

WCF從理論到實踐(6):WCF架構

WCF從理論到實踐(7):消息交換模式

WCF從理論到實踐(8):事件廣播

WCF從理論到實踐(9):實例模式和對象生命周期

WCF從理論到實踐(10):異常處理

WCF從理論到實踐(11)-異步

WCF從理論到實踐(12):事務

WCF從理論到實踐(13):事務投票

WCF從理論到實踐(14):WCF解決方案模板

WCF從理論到實踐(15):響應變化

WCF從理論到實踐(16):操作重載(帶視頻+ppt+源碼)

WCF從理論到實踐(17):OO大背離(帶視頻+ppt+源碼)

 

 

 

如果您懶得看下面的文字,您按下面的提示下載視頻教程,里面還有ppt和源代碼

請您到:http://downloads.cnblogs.com/jillzhang/wcf17.rar 下載視頻+課件+源碼,多謝dudu提供了這么好的交流空間。上篇文章中,大家提了好多好的建議,本次視頻文件大小已經大大減小,而且將pptx轉換成了ppt,多謝兄弟們的支持和幫助。以后想從事培訓,有此方面門路的兄弟如果能推薦一下,更是不勝感激。

 

 

概述

上文說到了WCF和傳統面向對象編程中不太一致的地方之一:操作重載(Operation Overload),本文講述WCF 另外一個不太符合OO之處:服務契約和數據契約的繼承關系。在面向對象的大原則中有下面兩個原則

1) 依賴倒置原則
2) Liskov替換原則

依賴倒置原則強調的是實現依賴于抽象,抽象不依賴于實現 ,而Liskov原則強調的是子類必須可以替換其基類,這在anytao大作<<你必須知道的.Net>>中都有詳細的闡述。本文無意闡述這兩個原則的細節,想了解OO原則的知識,可以閱讀王兄的大作。本文只探討WCF架構下對這兩個原則的辯證統一關系。

WCF架構的特征

在弄清楚WCF在上兩個OO原則矛盾統一的關系之前,我想有必要先了解WCF的架構,清楚了WCF架構之后,才能更清楚地明白為何WCF中對上述原則的辯證關系!我們先來看下WCF 通訊的工作原理

 

請看上面的WCF體系結構圖(該圖原出處《WCF服務編程》一書),從圖中我們看出WCF通訊雙方是存在明顯的分界的,盡管WCF也支持in-proc,但這種分界依然存在。我們知道接口和抽象類都是對現實世界的一種抽象描述,它們基于的是現實中的真實場景。比如公雞能報曉,猴子能上樹,老鼠能盜洞,公雞母雞都是雞,雞鴨鵝全是家禽等等。這些都是人類在長期社會生活中,對現實世界的一種認識!這種認識是存在地域特性的,比如有些地區視蛇為毒蟲猛獸,如果給蛇作個接口的話,會包含如下云云:void EatPeople();它會吃人,這種印象很不好,但是另外一些地區可能就將蛇作為圖騰,他們眼中蛇是神圣的,如果讓他們描述蛇,他們會說: void ProtectPeople();蛇能庇佑人類!同樣對事物的分類也是如此。隱喻到軟件開發中,我們在一個邊界下定義的接口規范和類的層次對于其他邊界下的系統是否一定通用呢?答案是否定的。在WCF中,服務與客戶是完全松散的耦合,他們之間完全沒有必要了解對方的具體實現,如果不是用到WCF,二者老死都可以不相往來。但二者之間加入WCF之后便有了聯系,我的理解是代理(Proxy)便是二者之間的紅娘,它起到了橋梁,紐帶,中介的作用。既然是中介,那么他就應該一碗水端平,不能因為服務端的自身問題給客戶端帶來不必要的負擔,反之亦然!也就是說WCF服務端定義的一些層級概念是服務端的規范,這些規范針對客戶端來說,是否適用,那要看客戶端的具體業務邏輯,所以代理這個紅娘就不能將服務端的邏輯強加給客戶端。下面我們就從服務契約(ServiceContract)的層級關系和數據協定(DataContract)的層級關系兩個方面看看WCF框架是如何體現上述的特征的。

服務契約的層級關系

閑言少敘,我們采用下面的場景來做演示,場景如下:

 

Mp3是一個能播放音樂的機器,而錄音機是一款能錄音的機器,當前的大部分手機呢,除了原有的接打電話,收發短信等功能,它還有一些擴展功能,比如播放音樂的功能,錄音的功能。而對于現實中某些個體而言,他可能只會用到手機功能的全部或者一部分,比如一個人用到了全部的功能,它所認識的手機便是:能播打電話,能收發短信,能放歌,能錄音的機器,而另外一個人他只用到放歌的功能,對于他來講,手機就= mp3播放器,同理,如果他只用到錄音功能,那在他看來手機就是個錄音機。

用程序實現如下,按照WCF實現的通常步驟,我們先來實現契約部分,契約部分我們定義三個服務契約:

IMp3.cs

[ServiceContract] 

public interface IMp3 



[OperationContract] 

void PlaySound(string soundFile); 

}
 

 

IRecorder.cs

[ServiceContract] 

public interface IRecorder 



[OperationContract] 

void Record(); 

}
 

 

ITelephone.cs

[ServiceContract] 

public interface ITelephone:IMp3,IRecorder 



[OperationContract] 

void Call(string to); 

[OperationContract] 

void Pickup(string from); 

[OperationContract] 

void ReceiveMessage(string from); 

[OperationContract] 

void SendMessage(string to); 

}
 

接下來,我們實現服務的實現部分,我們在服務實現中,只需要實現一個Telephoe便可以完成契約中全部的功能列表了

Telephone.cs

Telephone.cs 

 

此時我們先來看一下服務端服務契約的層級關系圖:

下面我們實現一個托管,這部分代碼不重要,和本文想要闡述的知識也不太相關,所以可以略過,只知道我們上一步中的服務已經被托管起來了。托管代碼為:

托管代碼

 

用Svcutil.exe生成代理文件Proxy.cs,打開它,我們會發現如下的代碼:

生成的代理代碼

 

從上面的代碼中可以看出客戶端代理的服務契約的層級關系如下:

從上面的圖和代理代碼中我們可以看出,ITelephone這個接口與Imp3,IRecorder之間已經沒有了繼承關系。而是直接將Imp3,IRecorder中的功能添加到了ITelephone中,這樣一來客戶端代理中的TelephoneClient便不依賴于IMp3和IRecorder,也就從根本上更改了他們之間的層次關系。這樣做的好處很明顯,如果客戶端需要全部功能,它只需要獲得ITelephone和TelephoneClient便可以了,客戶沒必要知道IMp3和IRecorder的存在。同樣針對IMp3和IRecorder也是這樣的道理。

數據契約的繼承關系

在面向對象中,Liskov強調的是任何時候,子類都應該能替換其基類,但在WCF中情形又有所改變,我們根據下面的情形來做演示程序

在服務端有一個訂單的數據協定Order,而在客戶端重新定義對象OrderDetail繼承Order,此時試圖用OrderDetail的實例替換Order實例調用WCF服務,會有什么結果?

 根據情形,我們寫如下代碼:

在服務端契約中,添加數據協定Order.cs

[DataContract] 

public class Order 



[DataMember] 

public string OrderName 



get

set

}
 

}
 

 

和使用該協定的服務契約IOrderManager.cs

IOrderManager.cs
IOrderManager.cs
[ServiceContract]
public interface IOrderManager
{
  [OperationContract]
  void Process(Order order);    
}

 

實現IOrderManager的服務為:OrderManager.cs

Code
using log = System.Console;

public class OrderManager : IOrderManager
{

     public void Process(Order order)
    {
        log.WriteLine("OrderManager is processing order.");
    }
}

 

此時,進行托管和生成代理類,代理類代碼如下:

生成

此時在客戶端增加一個OrderDetail類,使其繼承Order,代碼為: 

CodeOrderDetail.cs

 

我們先來查看一下當前在客戶端的類型的關系圖

從圖中我們可以清晰地看出OrderDetail繼承了OrderDetail,如果按照Liskov原則,用OrderDetail這個字類應該完全能替代Order這個基類。

此時我們編寫客戶端調用代碼如下:

 

IOrderManager orderService = new OrderManagerClient(new NetTcpBinding(), new EndpointAddress("net.tcp://127.0.0.1:1237/order")); 

Contracts.Order order 
= new Contracts.Order(); 

orderService.Process(order); 

Contracts.OrderDetail orderDetail 
= new Contracts.OrderDetail(); 

orderService.Process(orderDetail); 

執行的時候,便會在代碼orderService.Process(orderDetail);發生如下的異常:

由此可見,Liskov原則在WCF程序的服務端與客戶端之間是不適用的,原因在上圖的異常說明中已經描述的很清楚了。當然如果非要保持這種繼承關系,WCF也提供了相應的機制。但只是一種變相的策略,卻不是從根本上要校正此類問題。

小結

在面向對象中的依賴倒置和Liskov原則都是有邊界限制的,針對WCF來講,服務端所設定的契約關系層次和數據的繼承關系不能強制的適用于客戶端,這充分體現了面向服務的松散耦合的特征,雖然有悖于OO的設計原則,但也恰恰體現了面向服務的優點,且這種做法更適應變化。

視頻,課件以及源碼下載 

 

請您到:http://downloads.cnblogs.com/jillzhang/wcf17.rar 下載視頻+課件+源碼,多謝dudu提供了這么好的交流空間。上篇文章中,大家提了好多好的建議,本次視頻文件大小已經大大減小,而且將pptx轉換成了ppt,多謝兄弟們的支持和幫助。以后想從事培訓,有此方面門路的兄弟如果能推薦一下,更是不勝感激。
1
0
 
標簽:WCF
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()