首页 > 代码库 > 深入理解.NET设计模式(1)

深入理解.NET设计模式(1)

 

鸟随凤鸾,人伴贤良,得以共之,我之幸也。说的是鸟随着鸾凤可以飞的更高远,人和比自己境界高的相处,自己也会得到熏染进步。

一、概述

分享出来简单的心得,望探讨

依赖倒置

依赖注入

Adapter模式

Null模式

二、快速示例

 

部分代码:

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

ProductService直接依赖于ProductRepostory属于强耦合。假设客户新产品上架,需要将ProductRepository替换为NewProductRepository,那么就势必要修改ProductService以及所有引用类ProductRepository

 三、重构

1、依赖倒置

那么究竟何为依赖倒置,它又如何解耦呢。

依赖倒置实际就是就是要依赖于抽象,不要依赖于具体。意思就是面对抽象进行,而不是面对实现进行编程,通过抽象解决客户与实现模块间的耦合关系。依赖倒置两大重要的原则:一是高层模块不应依赖于低层模块,都应依赖于抽象,二是具体实现也应依赖于抽象。

来看怎么做,定义IProductRepostory接口,使ProductRepostory依赖于接口 ,对ProductService重构也依赖于接口

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

依赖倒置通过面对抽象从数据类型降低了耦合度,依赖倒置使高层模块依赖于抽象,即只关心new出来的是否是IProductRepository接口的对象而不关心new出来是谁。这样现在需要解决的就是具体实现的创建问题。

2、依赖注入

依赖注入从其初衷的角度解释就是:当类A完成某个工作需要创建B类的实例来协助的时候,把创建协助类B的工作提取出来从外部完成。

依赖注入三种形式:构造器,方法,属性。本文用构造器注入的方式介绍依赖注入

ProductService重构:

 1 public class ProductService 2     { 3         private IProductRepository _productRepository; 4         5  6         public ProductService(IProductRepository productRepository) 7         {            8             _productRepository = productRepository; 9             10         }11     12       ..................13 14          15     }
ProductService

测试代码(即外部):

 1 namespace Patterns.QuickDemp.Tests 2 { 3     [TestFixture] 4     public class ProductServiceTests 5     { 6         [Test] 7         public void Test_Client() 8         { 9              //外部创建对象,任何继承抽象的对象皆可注入10             AnyProductRepository anyproductrepository = new AnyProductRepository(); 11             //注入12             ProductService productService = new ProductService(anyproductrepository);13             ...........14             ..........15 16         }17 18 19     }20 }
Tests

 可以大胆的作如下设想:客户,商家,第三方支付的关系拿来类比,客户直接与商家交易是一种模式。现在依赖反转,银行卡,支付宝,现金券等支付方式全部继承某个接口,支付动作抽象出来,客户选择支付方式然后外部注入,第三方根据注入指定方式完成支付动作。

3、Adapter模式

 adapter模式意图描述:将一个类的接口转换成客户希望的接口

问题描述:用户自定义接口ICacheStorage.面向抽象过程中要让HttpContext成为一个实现用户自定义接口的实现。HttpContext是非用户编写的类,所以用到适配器模式

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

仍然依赖倒置依赖注入对Service重构如下:

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

4、Null Object 模式

空对象模式:在一些特殊的情况下用户不希望连带的执行某个动作,也不希望传递null在框架里做判断,就用到空对象模式。这个很容易理解,只是让附带动作变为do nothing 

 1 public class NullObjectCachingAdapter : ICacheStorage  2     {         3         public void Remove(string key) 4         { 5             // Do nothing 6         } 7  8         public void Store(string key, object data) 9         {10             // Do nothing11         }12 13         public T Retrieve<T>(string storageKey)14         {15             return default(T);16         }        17     }
NullObjectCachingAdapter

 

 四、小结