日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

Asp.net设计模式笔记之一:理解设计模式

發布時間:2025/5/22 asp.net 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Asp.net设计模式笔记之一:理解设计模式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

http://www.cnblogs.com/scy251147/p/3793547.html

GOF設計模式著作中的23種設計模式可以分成三組:創建型(Creational),結構型(Structural),行為型(Behavioral)。下面來做詳細的剖析。

創建型

創建型模式處理對象構造和引用。他們將對象實例的實例化責任從客戶代碼中抽象出來,從而讓代碼保持松散耦合,將創建復雜對象的責任放在一個地方,這遵循了單一責任原則和分離關注點原則。

下面是“創建型”分組中的模式:

1.Abstract Factory(抽象工廠)模式:提供一個接口來創建一組相關的對象。

2.Factory Method(工廠方法)模式:支持使用一個類來委托創建有效對象的責任。

3.Builder(生成器)模式:將對象本身的構造分離出來,從而能夠構造對象的不同版本。

4.Prototype(原型)模式:能夠從一個原型實例來復制或克隆類,而不是創建新實例。

5.Singleton(單例)模式:支持一個類只實例化一次,并只有一個可用來訪問它的全局訪問點。

結構型

結構型模式處理對象的組合與關系,以滿足大型系統的需要。

下面是“結構型”分組中的模式:

1.Adapter(適配器)模式:使不兼容接口的類能夠一起使用。

2.Bridge(橋接)模式:將抽象與其實現分離,允許實現和抽象彼此獨立地改變。

3.Composite(組合)模式:可以像對待對象的單個實例那樣來對待一組表示層次結構的對象。

4.Decorator(裝飾)模式:能夠動態包裝一個類并擴展其行為。

5.Facade(門面)模式:提供一個簡單的接口并控制對一組復雜接口和子系統的訪問。

6.Flyweight(享元)模式:提供一種在許多小類之間高效共享數據的方式。

7.Proxy(代理)模式:為一個實例化成本很高的更復雜的類提供一個占位符。

行為型

行為型模式處理對象之間在責任和算法方面的通信。這個分組中的模式將復雜行為封裝起來并將其從系統控制流中抽象出來,這樣就使復雜系統更容易理解和維護。

下面是”行為型“分組中的模式:

1.Chain Of Responsibility(責任鏈)模式:允許將命令動態鏈接起來處理請求。

2.Command(命令)模式:將一個方法封裝成一個對象,并將該命令的執行與它的調用者分離。

3.Interpreter(解釋器)模式:指定如何執行某種語言中的語句。

4.Iterator(迭代器)模式:提供以形式化的方式來導航集合的方法。

5.Mediator(中介者)模式:定義一個對象,可以讓其他兩個對象進行通信而不必讓它們知道彼此。

6.Memento(備忘錄)模式:允許將對象恢復到以前的狀態。

7.Observer(觀察者)模式:定義一個或多個類在另一個類發生變化時接到報警。

8.State(狀態)模式:允許對象通過委托給獨立的,可改變的狀態對象來改變自己的行為。

9.Strategy(策略)模式:能夠將算法封裝到一個類中并在運行時轉換,以改變對象的行為。

10.Template Method(模板方法)模式:定義算法流程控制,但允許子類重寫或實現執行步驟。

11.Vistor(訪問者)模式:能夠在類上執行新的功能而不影響類的結構。

上面介紹了眾多的設計模式及其分組。但是如何來選擇和運用呢?下面有一些需要注意的事項:

1.在不了解模式的情況下不能運用他們。

2.在設計的時候,要衡量是否有必要引入設計模式的復雜性。最好能衡量下實現某種模式所需的時間與該模式能夠帶來的效益。謹記KISS原則:保持簡單淺顯。

3.將問題泛化,以更抽象的方式識別正在處理的問題。設計模式是高層次的解決方案,試著把問題抽象,而且不要過于關注具體問題的細節。

4.了解具有類似性質的模式以及同組中的其他模式。以前已經使用過某個模式并不意味著在解決問題時它總是正確的模式選擇。

5.封裝變化的部分。了解應用程序中什么可能發生變化。如果知道某個特殊的報價折扣算法將隨時間發生變化,那么尋找一種模式來幫助您在不影響應用程序其余部分的情況下改變該算法。

6.在選擇好設計模式之后,確保在命名解決方案中的參與者時使用該模式的語言及領域語言。例如,如果正在使用策略模式為不同的快遞公司計價提供解決方案,那么相應地為他們明明,如FedExShippingCostStrategy。通過組合使用模式的公共詞匯表和領域語言,會讓代碼更具可讀性,而且更能夠讓其他具備模式知識的開發者理解。

?

就設計模式而言,除了學習之外沒有其他替代方法。對每種設計模式了解得越多,在運用他們時就會準備的更好。當遇到一個問題正在尋找解決方案時,掃描一下每種模式的目的,喚起自己的記憶。

一種很好地學習方法就是試著識別.net框架中的模式,比如:Asp.net Cache使用了Singleton模式,在創建新的Guid實例時使用了Factory Method模式,.Net 2 xml類使用Factory Method模式,而1.0版并沒有使用。

?

下面我們以一個快速模式示例來進行講解,以便于加深映像。

新建一個類庫項目0617.DaemonPattern.Service,然后引用System.web程序集。

首先添加一個Product.cs的空類作為我們的Model:

?
1 2 3 4 public class Product ?{ ?}

然后添加ProductRepository.cs類作為我們的數據存儲倉庫,從這里我們可以從數據庫獲取數據實體對象:

?
1 2 3 4 5 6 7 8 9 public class ProductRepository { ????public IList<Product> GetAllProductsIn(int categoryId) ????{ ????????var products = new List<Product>(); ????????//Database operation to populate products. ????????return products; ????} }

最后添加一個名稱為ProductService.cs的類,代碼如下:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class ProductService ???{ ???????public ProductService() ???????{ ???????????this.productRepository = new ProductRepository(); ???????} ???????private ProductRepository productRepository; ???????public IList<Product> GetAllProductsIn(int categoryId) ???????{ ???????????IList<Product> products; ???????????string storageKey = string.Format("products_in_category_id_{0}", categoryId); ???????????products = (List<Product>)HttpContext.Current.Cache.Get(storageKey); ???????????if (products == null) ???????????{ ???????????????products = productRepository.GetAllProductsIn(categoryId); ???????????????HttpContext.Current.Cache.Insert(storageKey, products); ???????????} ???????????return products; ???????} ???}

?

?

從代碼的邏輯,我們可以清楚的看到,ProductService通過ProductRepository倉庫從數據庫獲取數據。

這個類庫帶來的問題有以下幾點:

1.ProductService依賴于ProductRepository類。如果ProductRepository類中的API發生改變,就需要在ProductService類中進行修改。

2.代碼不可測試。如果不讓真正的ProductRepository類連接到真正的數據庫,就不能測試ProductService的方法,因為這兩個類之間存在著緊密耦合。另一個與測試有關的問題是,該代碼依賴于使用Http上下文來緩存商品。很難測試這種與Http上下文緊密耦合的代碼。

3.被迫使用Http上下文來緩存。在當前狀態,若使用Velocity或Memcached之類的緩存存儲提供者,則需要修改ProductService類以及所有其他使用緩存的類。Verlocity和Memcached都是分布式內存對象緩存系統,可以用來替代Asp.net的默認緩存機制。

隨意,綜上看來,代碼耦合度過高,不易進行測試,同時也不易進行替換。

?

既然知道了存在的問題,那么就讓我們來對其進行重構。

首先,考慮到ProductService類依賴于ProductRepository類的問題。在當前狀態中,ProductService類非常脆弱,如果ProductRepository類的API改變,就需要修改ProductService類。這破壞了分離關注點和單一職責原則

1.依賴倒置原則(依賴抽象而不要依賴具體)

可以通過依賴倒置原則來解耦ProductService類和ProductRepository類,讓它們都依賴于抽象:接口。

在ProductRepository類上面右擊,選擇“重構”->“提取接口”選項,會自動給我們生成一個IProductRepository.cs類:

?
1 2 3 4 public interface IProductRepository ????{ ????????IList<Product> GetAllProductsIn(int categoryId); ????}

修改現有的ProductRepository類,以實現新創建的接口,代碼如下:

?
1 2 3 4 5 6 7 8 9 public class ProductRepository : IProductRepository ???{ ???????public IList<Product> GetAllProductsIn(int categoryId) ???????{ ???????????var products = new List<Product>(); ???????????//Database operation to populate products. ???????????return products; ???????} ???}

?

之后更新ProductService類,以確保它引用的是接口而非具體:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class ProductService ????{ ????????public ProductService() ????????{ ????????????this.productRepository = new ProductRepository(); ????????} ?? ????????private IProductRepository productRepository; ?? ????????public IList<Product> GetAllProductsIn(int categoryId) ????????{ ????????????IList<Product> products; ????????????string storageKey = string.Format("products_in_category_id_{0}", categoryId); ????????????products = (List<Product>)HttpContext.Current.Cache.Get(storageKey); ????????????if (products == null) ????????????{ ????????????????products = productRepository.GetAllProductsIn(categoryId); ????????????????HttpContext.Current.Cache.Insert(storageKey, products); ????????????} ????????????return products; ????????} ????}

這樣修改之后,ProductService類現在只依賴于抽象而不是具體的實現,這意味著ProductService類完全不知道任何實現,從而確保它不是那么容易的被破壞掉,而且代碼在整體上說來對變化更有彈性。

但是,這里還有個問題,既是ProductService類仍然負責創建具體的實現。而且目前在沒有有效的ProductRepository類的情況下不可能測試代碼。所以這里我們需要引入另一個設計原則來解決這個問題:依賴注入原則。

由于ProductService類仍然與ProductRepository的具體實現綁定在了一起,通過依賴注入原則,我們可以將這一過程移到外部進行,具體方法就是通過該類的構造器將其注入:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class ProductService ????{ ????????public ProductService(IProductRepository productRepository) ????????{ ????????????this.productRepository = productRepository; ????????} ?? ????????private IProductRepository productRepository; ?? ????????public IList<Product> GetAllProductsIn(int categoryId) ????????{ ????????????IList<Product> products; ????????????string storageKey = string.Format("products_in_category_id_{0}", categoryId); ????????????products = (List<Product>)HttpContext.Current.Cache.Get(storageKey); ????????????if (products == null) ????????????{ ????????????????products = productRepository.GetAllProductsIn(categoryId); ????????????????HttpContext.Current.Cache.Insert(storageKey, products); ????????????} ????????????return products; ????????} ????}

這樣就可以在測試期間向ProductService類傳遞替代者,從而能夠孤立地測試ProductService類。通過把獲取依賴的責任從ProductService類中移除,能夠確保ProductService類遵循單一職責原則:它現在只關心如何協調從緩存或資源庫中檢索數據,而不是創建具體的IProductRepository實現。

依賴注入有三種形式:構造器,方法以及屬性。我們這里只是使用了構造器注入。

當然,現在的代碼看上去基本沒問題了,但是一旦替換緩存機制的話,將會是一個比較棘手的問題,因為基于Http上下文的緩存沒有被封裝,替換其需要對當前類進行修改。這破壞了開放封閉原則:對擴展開放,對修改關閉。

由于Adapter(適配器)模式主要用來將一個類的某個轉換成一個兼容的接口,所以在當前的例子中,我們可以將HttpContext緩存API修改成想要使用的兼容API。然后可以使用依賴注入原則,通過一個接口將緩存API注入到ProductService類。

這里我們創建一個名為ICacheStorage的新街口,它包含有如下契約:

?
1 2 3 4 5 6 public interface ICacheStorage ???{ ???????void Remove(string key); ???????void Store(string key, object data); ???????T Retrieve<T>(string key); ???}

在ProductService類中,我們就可以將其取代基于HttpContext的緩存實例:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class ProductService ????{ ????????public ProductService(IProductRepository productRepository,ICacheStorage cacheStroage) ????????{ ????????????this.productRepository = productRepository; ????????????this.cacheStroage = cacheStroage; ????????} ?? ????????private IProductRepository productRepository; ????????private ICacheStorage cacheStroage; ?? ????????public IList<Product> GetAllProductsIn(int categoryId) ????????{ ????????????IList<Product> products; ????????????string storageKey = string.Format("products_in_category_id_{0}", categoryId); ????????????products = cacheStroage.Retrieve<List<Product>>(storageKey); ????????????if (products == null) ????????????{ ????????????????products = productRepository.GetAllProductsIn(categoryId); ????????????????cacheStroage.Store(storageKey, products); ????????????} ????????????return products; ????????} ????}

而具體的緩存類我們可以繼承自ICacheStorage來實現:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class HttpCacheAdapterStorage:ICacheStorage ????{ ????????public void Remove(string key) ????????{ ????????????if (HttpContext.Current.Cache[key] != null) ????????????????HttpContext.Current.Cache.Remove(key); ????????} ?? ????????public void Store(string key, object data) ????????{ ????????????if (HttpContext.Current.Cache[key] != null) ????????????????HttpContext.Current.Cache.Remove(key); ????????????HttpContext.Current.Cache.Insert(key,data); ????????} ?? ????????public T Retrieve<T>(string key) ????????{ ????????????if(HttpContext.Current.Cache[key]!=null) ????????????????return (T)HttpContext.Current.Cache[key]; ????????????return default(T); ????????} ????}

現在再回頭看看,我們解決了開始列舉的種種問題,使得代碼更加容易測試,更易讀,更易懂。

下面是Adapter(適配器)模式的UML圖示:

從圖中可以看出,客戶有一個對抽象(Target)的引用。在這里,該抽象就是ICacheStorage接口。Adapter是Target接口的一個實現,它只是將Operation方法委托給Adaptee類,這里的Adapter類就是指我們的HttpCacheStorage類,而Adaptee類則是指HttpContext.Current.Cache提供的具體操作方法。

具體的描述如下:

這樣,當我們切換到Memcached,抑或是MS Velocity的時候,只需要創建一個Adapter,讓ProductService類與該緩存存儲提供者通過公共的ICacheStorage接口交互即可。

?

?

?

從這里我們知道:

Adapter模式非常簡單,它唯一的作用就是讓具有不兼容接口的類能夠在一起工作。

由于Adapter模式并不是唯一能夠幫助處理緩存數據的模式,下面的章節將會研究Proxy設計模式如何來幫助解決緩存問題的。

?

在這里,我們還有最后一個問題沒有解決,就是在當前設計中,為了使用ProductService類,總是不得不為構造器提供ICacheStorage實現,但是如果不希望緩存數據呢? 一種做法是提供一個null引用,但是這意味著需要檢查空的ICacheStorage實現從而弄亂代碼,更好的方式則是使用NullObject模式來處理這種特殊情況。

Null Object(空對象模式,有時也被稱為特殊情況模式)也是一種極為簡單的模式。當不希望指定或不能指定某個類的有效實例而且不希望到處傳遞null引用時,這個模式就有用武之地。Null對象的作用是代替null引用并實現相同的接口但是沒有行為

如果不希望ProductService類中緩存數據,Null Object模式可以派上用場:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class NullObjectCache:ICacheStorage ????{ ????????public void Remove(string key) ????????{ ????????} ?? ????????public void Store(string key, object data) ????????{ ????????} ?? ????????public T Retrieve<T>(string key) ????????{ ????????????return default(T); ????????} ????}

這樣,當我們請求緩存數據的時候,它什么都不做而且總是向ProductService返回null值,確保不會緩存任何數據。

?

最后,總結一下:

三種設計模式分組。

依賴注入原則。

Adapter模式具體應用。

Null Object模式用于處理空對象。

轉載于:https://www.cnblogs.com/aaa6818162/p/3963704.html

總結

以上是生活随笔為你收集整理的Asp.net设计模式笔记之一:理解设计模式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。