首先,我们虚拟一个系统环境(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 : ICacheStoragepublic 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; } }}
附上重构后的设计图:
时间: 2024-10-10 23:02:54