以下實做的SourceCode已經放到GitHub :
https://github.com/toyo0103/Demo_EditTemplate_1
最近在幫專案成員導入開發分層以及物件導向的觀念,也想把這Demo的過程記錄下來。畢竟想法可能隨著專案的經歷而不斷的在修正,也可藉此不斷回頭檢視自己的基本功是否足夠
一、首先來看一下專案分層的關聯圖
[![](https://2.bp.blogspot.com/-2uYHHE-iq7c/V7JxJbl6gCI/AAAAAAAAH3w/I-gYOBfJq8U_fLoVSQTuySsCtNMSb9J6ACLcB/s1600/1.png)](https://2.bp.blogspot.com/-2uYHHE-iq7c/V7JxJbl6gCI/AAAAAAAAH3w/I-gYOBfJq8U_fLoVSQTuySsCtNMSb9J6ACLcB/s1600/1.png)
Application : 應用層,參考了邏輯層
Service : 邏輯層,參考了資料存取層
Repository : 資料存取層
Lib : 共用層 ,被Application、Service、Repository參考
二、目前各層尚未重構的程式
[![](https://2.bp.blogspot.com/-tg5bIS8XXLo/V7Kv7donQqI/AAAAAAAAH4A/LMM962SvdT8znywny9YxnzQbnxKS0H-oQCLcB/s1600/1.png)](https://2.bp.blogspot.com/-tg5bIS8XXLo/V7Kv7donQqI/AAAAAAAAH4A/LMM962SvdT8znywny9YxnzQbnxKS0H-oQCLcB/s1600/1.png)
模擬A廠商提供的POI(地圖座標點)資料
1 | /// <summary> |
****Service層
[![](https://4.bp.blogspot.com/-Bcv7-vwubuU/V7KxJwqZf9I/AAAAAAAAH4I/9vgY1F6fzbI28ZdK-OCZZmF9bzaM9_FJQCLcB/s1600/1.png)](https://4.bp.blogspot.com/-Bcv7-vwubuU/V7KxJwqZf9I/AAAAAAAAH4I/9vgY1F6fzbI28ZdK-OCZZmF9bzaM9_FJQCLcB/s1600/1.png)
**
****
**傳入頻道代碼,依據頻道底下的類別,去各供應商取得POI資料,目前模擬頻道資料如下
[![](https://4.bp.blogspot.com/-e-CVa7nJHGo/V7KxhdAVBQI/AAAAAAAAH4M/4xbGZY9o5JE9Dg6fnyvtWQOmm0wMKcDXgCLcB/s320/1.png)](https://4.bp.blogspot.com/-e-CVa7nJHGo/V7KxhdAVBQI/AAAAAAAAH4M/4xbGZY9o5JE9Dg6fnyvtWQOmm0wMKcDXgCLcB/s1600/1.png)
頻道1底下有一個交通的類別,該類別的POI資料來源為A廠商提供
頻道2底下有一個交通的類別,該類別的POI資料來源為A廠商與B廠商提供的總和
1 | public class POIService |
Application層
將傳入的ID透過Service去取得POI資料,並解用Json回傳 **
**
```csharp
public ActionResult Index(string id)
{
var Service = new POIService();
var POIs = Service.Get(id);
return Json(POIs,JsonRequestBehavior.AllowGet);
}
1 |
|
Service層
1 | //逐一搜尋頻道底下的各類別 |
執行結果
[![](https://3.bp.blogspot.com/-oLBfowU5dPE/V7K3te4Ug8I/AAAAAAAAH4w/HWxKp39vbfwkUb4zpQkvoB_umOlCnBk2gCLcB/s1600/1.png)](https://3.bp.blogspot.com/-oLBfowU5dPE/V7K3te4Ug8I/AAAAAAAAH4w/HWxKp39vbfwkUb4zpQkvoB_umOlCnBk2gCLcB/s1600/1.png)
[![](https://3.bp.blogspot.com/-At8pfSKZU1A/V7O464uATbI/AAAAAAAAH6Y/_ZteovVvDKgiWIP4C7VOW0d_ID0T3Yn0gCLcB/s640/1.png)](https://3.bp.blogspot.com/-At8pfSKZU1A/V7O464uATbI/AAAAAAAAH6Y/_ZteovVvDKgiWIP4C7VOW0d_ID0T3Yn0gCLcB/s1600/1.png)
[![](https://4.bp.blogspot.com/-_mL7zcPN80s/V7O5MABxbiI/AAAAAAAAH6c/iwdP7xw3pVkJlb08t52ggMFcpuNRywTZQCLcB/s640/1.png)](https://4.bp.blogspot.com/-_mL7zcPN80s/V7O5MABxbiI/AAAAAAAAH6c/iwdP7xw3pVkJlb08t52ggMFcpuNRywTZQCLcB/s1600/1.png)
那該怎麼改可以避免每次改Repository又要一直改Service層呢?
這時就會運用到OO原則中的**依賴抽象**概念,當我們面對的是實體(例如:**ASupplierRepository** , **BSupplierRepository**)時也就是所謂的高耦合,如果面對的實體有所變動時,所有耦合的地方都會有高機率要一起改動的風險。
因為要面對抽象,第一步我們就要來觀察這兩個實體共通處是什麼? 其實說穿了都是提供一個叫做Get()的方法,當呼叫他時,回傳對應的POI List,這就是它們共通的地方,接下來透過抽取介面的方式來實行隔離
**
****
**[![](https://1.bp.blogspot.com/-8ZNSvrUREs8/V7O5d9RkdPI/AAAAAAAAH6g/l9zIPDnhW2MYl-bCWyutTDSp9UeRtpDigCLcB/s640/1.png)](https://1.bp.blogspot.com/-8ZNSvrUREs8/V7O5d9RkdPI/AAAAAAAAH6g/l9zIPDnhW2MYl-bCWyutTDSp9UeRtpDigCLcB/s1600/1.png)
**
****ISupplierRepository**
1 | /// <summary> |
將ASupplierRepository , BSupplierRepository都套上介面
[![](https://3.bp.blogspot.com/-Jcpo5G8HHb0/V7K7uHZpu4I/AAAAAAAAH5I/uBTimpbb1_YxzjwVDH3ApMka-KNPy-fBwCLcB/s640/1.png)](https://3.bp.blogspot.com/-Jcpo5G8HHb0/V7K7uHZpu4I/AAAAAAAAH5I/uBTimpbb1_YxzjwVDH3ApMka-KNPy-fBwCLcB/s1600/1.png)
[![](https://2.bp.blogspot.com/-e3WLuMtpxh4/V7K7kaOISdI/AAAAAAAAH5E/ZLhqJrVmBcMxApVZcO82qEAbAGXsNTcaACLcB/s640/1.png)](https://2.bp.blogspot.com/-e3WLuMtpxh4/V7K7kaOISdI/AAAAAAAAH5E/ZLhqJrVmBcMxApVZcO82qEAbAGXsNTcaACLcB/s1600/1.png)
將兩個類別都實作了ISupplierRepository介面後,來修改**Service層**,讓它能面對抽象而非直接面對實體
Service層
首先先運用簡單工廠模式,請它來幫我們建造SupplierRepository的實體
[![](https://2.bp.blogspot.com/-sUw1JL2z37U/V7K9OulK-EI/AAAAAAAAH5Y/VeGijYdLK7ElsbQb0Cie22U4PnGOex-BwCLcB/s1600/1.png)](https://2.bp.blogspot.com/-sUw1JL2z37U/V7K9OulK-EI/AAAAAAAAH5Y/VeGijYdLK7ElsbQb0Cie22U4PnGOex-BwCLcB/s1600/1.png)
```
修改原本的POIService,讓它透過工廠來取得Repository,而不是直接去New實體
[![](https://1.bp.blogspot.com/-yqxvmh12FqM/V7K97eMgJOI/AAAAAAAAH5c/jeYldicOfYYSTvZJeGJRKOkPtJ7OETKXwCLcB/s640/1.png)](https://1.bp.blogspot.com/-yqxvmh12FqM/V7K97eMgJOI/AAAAAAAAH5c/jeYldicOfYYSTvZJeGJRKOkPtJ7OETKXwCLcB/s1600/1.png)
瞬間乾淨很多,而且POIService不再直接對ASupplierRepository , BSupplierRepository,而是面對ISupplierRepository,達成了所謂的面對抽象。
這時候思考一下,以後新增供應商的Repository時POIService都不用改動了,只要Repository層新增好後,將Factory改一下即可,但是否又跳出另一個問題了。這樣Repository層更動時還不是要打開Service層去做修改。 因此在這我會將Factory搬Repository層去封裝起來
將SupplierFactory搬到Repository層,並將實體Repository改成Internal封裝起來
[![](https://2.bp.blogspot.com/-WrLZP8-uAWU/V7LAj2T_ieI/AAAAAAAAH5s/uZ2PH9JQGX4X1aOwYavGDKaCHKfXC95MQCLcB/s1600/1.png)](https://2.bp.blogspot.com/-WrLZP8-uAWU/V7LAj2T_ieI/AAAAAAAAH5s/uZ2PH9JQGX4X1aOwYavGDKaCHKfXC95MQCLcB/s1600/1.png)
[![](https://2.bp.blogspot.com/-6shnp4lJN7Q/V7LA6VF0OmI/AAAAAAAAH5w/7eVfEwIFG38IGqtWYLxr-QDBdIAHtw1_wCLcB/s400/1.png)](https://2.bp.blogspot.com/-6shnp4lJN7Q/V7LA6VF0OmI/AAAAAAAAH5w/7eVfEwIFG38IGqtWYLxr-QDBdIAHtw1_wCLcB/s1600/1.png)
[![](https://2.bp.blogspot.com/-OMNNg00W0qE/V7LBG6V83fI/AAAAAAAAH50/1stqCDyKtRMLmxt-QBvl3vXZ9khxZOFpACLcB/s400/1.png)](https://2.bp.blogspot.com/-OMNNg00W0qE/V7LBG6V83fI/AAAAAAAAH50/1stqCDyKtRMLmxt-QBvl3vXZ9khxZOFpACLcB/s1600/1.png)
換句話說,因為改成Internal的關係,現在Service層也碰不到**ASupplierRepository** , **B****SupplierRepository**這兩個實體了,完全只能依賴Factory來取得介面的對應實體,未來不管怎麼新增Repository都不會再改**Service層**,到這邊就是重構並且實踐多型了
目前UML結構圖如下
[![](https://1.bp.blogspot.com/-fUMrd2aOxZs/V7LGMRcCTpI/AAAAAAAAH6I/lgwJmCO6LYse8DXoFEJKw3NqwtL7Z7f7QCLcB/s1600/1.png)](https://1.bp.blogspot.com/-fUMrd2aOxZs/V7LGMRcCTpI/AAAAAAAAH6I/lgwJmCO6LYse8DXoFEJKw3NqwtL7Z7f7QCLcB/s1600/1.png)