码迷,mamicode.com
首页 > 其他好文 > 详细

利用依赖倒置和依赖注入实现应用程序解耦

时间:2015-06-10 20:40:19      阅读:132      评论:0      收藏:0      [点我收藏+]

标签:

首先,我们虚拟一个系统环境(e-Shop),即网上商店的应用程序,其中有一个应用: 获取指定分类下的所有产品信息。我们按照传统的思路来实现。图1展示了系统的设计图。

技术分享

新建一个类库工程EShop.Service. 然后添加相应的类到工程中。

技术分享

技术分享

namespace EShop.Service
{
public class Product
{
}

public class ProductRepository
{
public IList<Product> GetProductsByCategory(int categoryId)
{
IList<Product> products = new List<Product>();
//进行数据库操作
return products;
}
}

public class ProductService
{
private ProductRepository productRepository;

public ProductService()
{
productRepository = new ProductRepository();
}

public IList<Product> GetProductsByCategory(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.GetProductsByCategory(categoryId);
HttpContext.Current.Cache.Insert(storageKey, products);
}
return products;
}
}
}

技术分享

从以上的程序段是否能发现不合理之处呢?我归纳了一下,大致有以下几点:

1. ProductService依赖于ProductRepository,一旦后者的API发生变化,则前者必然跟着发生变化。

2. 难以测试ProductService的方法,因为ProductRepository并未真正连接到数据库,另外还依赖于HttpContext,两者之间紧耦合。

3. 目前采用HttpContext来进行缓存,如果要更换缓存机制(如:Velocity或Memcached),ProductService将进行更改。

基于以上几点不合理之处,我们将一一进行重构和优化。

针对1:我们采用依赖倒置原则(Dependency Inversion Principle)——依赖于抽象而不是具体实现来解决。我们加入了接口IProductRepository。

技术分享

技术分享

public interface IProductRepository
{
IList<Product> GetProductsByCategory(int categoryId);
}
public class ProductRepository : IProductRepository
{
//...
}
public class ProductService
{
private IProductRepository productRepository;

public ProductService()
{
productRepository = new ProductRepository();
}
//...
}

技术分享

针对2:我们采用依赖注入原则(Dependency Injection Principle)——通过将抽象注入到构造函数、方法或属性来解决。我们修改ProductService构造函数。

技术分享

技术分享

public class ProductService
{
private IProductRepository productRepository;

public ProductService(IProductRepository productRepository)
{
this.productRepository = productRepository;
}
//...
}

技术分享

针对3:我们采用适配器模式(Adapter Pattern)——转换已有接口与客户期望的目标接口使之兼容来解决。我们添加了接口ICacheStorage和类HttpContextCacheAdapter。

技术分享

技术分享

public interface ICacheStorage
{
void Remove(string key);
void Store(string key, object data);
T Retrieve<T>(string key);
}

public class HttpContextCacheAdapter : ICacheStorage
public class HttpContextCacheAdapter : ICacheStorage
{
public void Remove(string key)
{
HttpContext.Current.Cache.Remove(key);
}

public void Store(string key, object data)
{
HttpContext.Current.Cache.Insert(key, data);
}

public T Retrieve<T>(string key)
{
T item = (T)HttpContext.Current.Cache.Get(key);
if (item == null)
{
item = default(T);
}
return item;
}
}

public class ProductService
{
private IProductRepository productRepository;
private ICacheStorage cacheStorage;

public ProductService(IProductRepository productRepository, ICacheStorage cacheStorage)
{
this.productRepository = productRepository;
this.cacheStorage = cacheStorage;
}

public IList<Product> GetProductsByCategory(int categoryId)
{
IList<Product> products;
string storageKey = String.Format("products_in_category_id_{0}", categoryId);
products = cacheStorage.Retrieve<List<Product>>(storageKey);
if (products == null)
{
products = productRepository.GetProductsByCategory(categoryId);
cacheStorage.Store(storageKey, products);
}
return products;
}
}

技术分享

综合以上的解决方案,这里贴出重构后完整的代码:

技术分享

技术分享

namespace EShop.Service
{
public class Product
{
}

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

public class ProductRepository : IProductRepository
{
public IList<Product> GetProductsByCategory(int categoryId)
{
IList<Product> products = new List<Product>();
//进行数据库操作
return products;
}
}

public interface ICacheStorage
{
void Remove(string key);
void Store(string key, object data);
T Retrieve<T>(string key);
}

public class HttpContextCacheAdapter : ICacheStorage
{
public void Remove(string key)
{
HttpContext.Current.Cache.Remove(key);
}

public void Store(string key, object data)
{
HttpContext.Current.Cache.Insert(key, data);
}

public T Retrieve<T>(string key)
{
T item = (T)HttpContext.Current.Cache.Get(key);
if (item == null)
{
item = default(T);
}
return item;
}
}

//有时为方便起见,我们定义空对象(空缓存适配器)
public class NullCacheAdapter : ICacheStorage
{
public void Remove(string key)
{
}

public void Store(string key, object data)
{
}

public T Retrieve<T>(string key)
{
return default(T);
}
}

public class ProductService
{
private IProductRepository productRepository;
private ICacheStorage cacheStorage;

public ProductService(IProductRepository productRepository, ICacheStorage cacheStorage)
{
this.productRepository = productRepository;
this.cacheStorage = cacheStorage;
}

public IList<Product> GetProductsByCategory(int categoryId)
{
IList<Product> products;
string storageKey = String.Format("products_in_category_id_{0}", categoryId);
products = cacheStorage.Retrieve<List<Product>>(storageKey);
if (products == null)
{
products = productRepository.GetProductsByCategory(categoryId);
cacheStorage.Store(storageKey, products);
}
return products;
}
}
}

技术分享

附上重构后的设计图:

技术分享

利用依赖倒置和依赖注入实现应用程序解耦

标签:

原文地址:http://www.cnblogs.com/Redvelvet/p/4567055.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!