zoukankan      html  css  js  c++  java
  • 设计模式备忘录(1):适配器模式、依赖注入依赖倒置、空对象模式

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

    一、概述

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

    依赖倒置

    依赖注入

    Adapter模式

    Null模式

    二、快速示例

    从一个简单的示例开始,业务流程Client通过Service查询产品,基础大概框架如下

     

    关键代码:

     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 ICacheStorage
    2     {
    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 nothing
    11         }
    12 
    13         public T Retrieve<T>(string storageKey)
    14         {
    15             return default(T);
    16         }        
    17     }
    NullObjectCachingAdapter

     四、小结

    通过依赖注入和依赖倒置,把创建什么样对象的工作交给客户端(Client),降低Service、Repository、Cache之间的耦合度。假如有新的产品,只有实现了IRepositiry接口,在客户端创建对象,注入给service的构造函数就可以了。




    1、如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!
    2、欢迎各位转载,但是未经作者本人同意,转载文章请在文章页面明显位置标明作者和原文连接,否则保留追究法律责任的权利。
    作者博客: http://www.cnblogs.com/xmai/
  • 相关阅读:
    jvisualm 结合 visualGC 进行jvm监控,并分析垃圾回收
    linux 查看服务器cpu 与内存配置
    arthas 使用总结
    selinux contexts 安全上下文的临时更改
    Android 8.1 Doze模式分析(五) Doze白名单及Debug方式
    Window 任意窗口置顶软件Window TopMost Control
    Android ApkToolPlus一个可视化的跨平台 apk 分析工具
    SVN Please execute the 'Cleanup' command.
    Android 如何在64位安卓系统中使用32位SO库
    Android cmd命令查看apk是32位还是64位?
  • 原文地址:https://www.cnblogs.com/xmai/p/Patterns_L01.html
Copyright © 2011-2022 走看看