首页 > 代码库 > 深入理解.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直接依赖于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 }
依赖倒置通过面对抽象从数据类型降低了耦合度,依赖倒置使高层模块依赖于抽象,即只关心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 }
测试代码(即外部):
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 }
可以大胆的作如下设想:客户,商家,第三方支付的关系拿来类比,客户直接与商家交易是一种模式。现在依赖反转,银行卡,支付宝,现金券等支付方式全部继承某个接口,支付动作抽象出来,客户选择支付方式然后外部注入,第三方根据注入指定方式完成支付动作。
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 }
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 }
仍然依赖倒置依赖注入对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 }
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 }