转载

使用设计模式,到底有什么好处?举例说明

在学习设计模式中,你是否也曾经拿着一本介绍23种设计模式,啃概念、uml、实现方式,但之后感觉是看与没看没什么区别,这里有个例子,足够简单地让人感觉到设计的好处;

例子实现的功能:根据一个分类返回所有的商品,并缓存

例如 京东,根据笔记本分类id http://list.jd.com/list.html?cat=670,671,672

几个类图关系如下:

使用设计模式,到底有什么好处?举例说明

ProductService class:

 public class ProductService {  private ProductRepository _productRepository;  public ProductService()  {   _productRepository = new ProductRepository();  }  /// <summary>  ///   /// </summary>  /// <param name="categoryId"></param>  /// <returns></returns>  public IList<Product> GetAllProByCategoryId(int categoryId)  {   IList<Product> products;   string cacheKey = string.Format("products_in_category_id_{0}",categoryId);   products = (IList<Product>)HttpContext.Current.Cache.Get(cacheKey);   if (products == null)   {    products = _productRepository.GetAllProByCategoryId(categoryId);    HttpContext.Current.Cache.Insert(cacheKey, products);   }   return products;  } }   

ProductRepository class:

 public class ProductRepository {  public IList<Product> GetAllProByCategoryId(int categoryId)  {   IList<Product> products = new List<Product>();   //get data for database   return products;  } }  

Product class:

    public class Product     {         public int id { get; set; }         public string name { get; set; }     }  

以上就简单实现了根据分类id 查询所有商品的功能,这里有几个问题:

  1. ProductService依赖于ProductRepository,ProductRepository的修改会影响它。
  2. ProductService不可测试,必须先实现ProductRepository里面操作数据库的方法,才能进行,紧耦合。
  3. 指定HTTP上下做缓存,之后难拓展,例如:之后需要换为Memcached或Redis做缓存,就要修改所有用到HTTP缓存的地方

用设计模式与面向对象设计原则解决以上问题

重构后:

ProductService class

 public class ProductService {  //解决问题1,重构ProductRepository令其基于接口,这里依赖于接口,不依赖于具体类:《依赖倒置原则》  private IProductRepository _productRepository;  //解决问题3,因为没有HTTP缓存的源码,不能按照基于接口的方式重构,可以用适配器(Adapter)模式转化为统一接口;  private ICacheStorage _cacheStorage;  //解决问题2,不创建实例,依赖外面传入:《依赖注入原则》  public ProductService(IProductRepository productRepository, ICacheStorage cacheStorage)  {   _productRepository = productRepository;   _cacheStorage = cacheStorage;  }  /// <summary>  /// 获取一个分类下的所有商品  /// </summary>  /// <param name="categoryId"></param>  /// <returns></returns>  public IList<Product> GetAllProByCategoryId(int categoryId)  {   IList<Product> products;   string cacheKey = string.Format("products_in_category_id_{0}", categoryId);   //products = (IList<Product>)HttpContext.Current.Cache.Get(cacheKey);   products = _cacheStorage.Get<IList<Product>>(cacheKey);   if (products == null)   {    products = _productRepository.GetAllProByCategoryId(categoryId);    //HttpContext.Current.Cache.Insert(cacheKey, products);    _cacheStorage.Add(cacheKey, products);   }   return products;  } }  

IProductRepository:

    public interface IProductRepository     {         IList<Product> GetAllProByCategoryId(int categoryId);     }

ProductRepository:

 public class ProductRepository : IProductRepository {  public IList<Product> GetAllProByCategoryId(int categoryId)  {   IList<Product> products = new List<Product>();   //get data for database   return products;  } }   

ICacheStorage :

    public interface ICacheStorage     {         void Delete(string key);         void Add(string key, object data);         T Get<T>(string key);     }  

HttpCacheAdapter :

 public class HttpCacheAdapter :ICacheStorage {  public void Delete(string key)  {   HttpContext.Current.Cache.Remove(key);  }  public void Add(string key, object data)  {   HttpContext.Current.Cache.Insert(key, data);  }  public T Get<T>(string key)  {   return (T)HttpContext.Current.Cache.Get(key);  } }   

最后,添加一个ProductRepository模拟返回数据

  public class ProductRepository_ForTest : IProductRepository {  /// <summary>  /// 在数据库操作未完成情况下,使用返回模拟数据,可以继续测试Service层的逻辑;  /// </summary>  /// <param name="categoryId"></param>  /// <returns></returns>  public IList<Product> GetAllProByCategoryId(int categoryId)  {   IList<Product> products = new List<Product>();   Product one = new Product();   one.id = 1;   one.name = "AA";   products.Add(one);   one = new Product();   one.id = 2;   one.name = "BB";   products.Add(one);   return products;  } }  

两个方式如何使用呢?使用控制台调用例子:

 class Program {  static void Main(string[] args)  {   //====== 没重构前调用 =======   int category = 1;   NoPatterns.ProductService noPatternsService = new NoPatterns.ProductService();   IList<NoPatterns.Product> products = noPatternsService.GetAllProByCategoryId(category);   //======= 重构后的调用 ======   //在数据库操作未完成情况下,可使用返回模拟数据;   YesPatterns.ProductRepository_ForTest productRepository = new ProductRepository_ForTest();   //基于数据库真实操作;     //YesPatterns.ProductRepository productRepository = new YesPatterns.ProductRepository();   //这样做的好处:数据库未准备好,也可以完成并测试Service层的逻辑,不用依赖;   //使用http上下缓存   YesPatterns.HttpCacheAdapter cache = new HttpCacheAdapter();   //使用Memcached缓存;   //YesPatterns.MemCachedAdapter cache = new MemCachedAdapter();   //这样做的好处:方便拓展,灵活,例如网站访问量大了,使用Http上下文缓存会力不从心,可以方便换为分布式的缓存,例如Memcached   //再例如:可以两种缓存方式一起使用。与用户相关缓存,使用Http;全局通用的缓存用Memcached;   YesPatterns.ProductService yesPatternsService = new YesPatterns.ProductService(productRepository, cache);   yesPatternsService.GetAllProByCategoryId(category);  } }   

完整例子代码已经放到github, 点击前往

正文到此结束
Loading...