适配器模式(结构型)
定义:
将一个类的接口转换成客户希望的另一个接口, 使得原本由于接口不兼容不能再一起工作的类,可以在一起工作
假设场景:
1、取数据,先看缓存中是否存在,有缓存取缓存,不存在时取数据库中的数据。
首先需要一个产品类
1 public class Project
2 {
3 public string Id { get; set; }
4 public string Name { get; set; }
5 }
定义IProjectRepository接口
public interface IProjectRepository
{
IList<Project> GetAllProject(int id);
}
实现IProjectRepository
public class ProjectRepository : IProjectRepository
{
public IList<Project> GetAllProject(int id)
{
IList<Project> project = new List<Project>();
return project;
}
}
创建ProjectService类 去实现业务
public class ProjectService
{
private IProjectRepository _projectRepository;
public ProjectService(IProjectRepository iprojectRepository)
{
_projectRepository = iprojectRepository;
}
public IList<Project> GetProject(int id)
{
IList<Project> data = null;
data = _projectRepository.GetAllProject(0);
return data;
}
}
PeojctService类现在只依赖与抽象而不是具体的实现,不知道具体的实现,从而确保它不会被轻易的破坏,使得代码在整体上对变化更有弹性。但是PeojctService类依旧负责创建具体对象的事情,所以我们可以使用依赖注入解决这个问题。
现在想要优化一下这个类,需要用到缓存,首先想到的应该是定义缓存接口,实现接口,调用完事。。但是由于没有HTTPContext类的源代码,因此不能像上面ProjectRepository 类那样做。
Adapter模式就能解决这个问题,下面根据适配器模式来进行缓存的实现。
如图所示;首先定义一个ICacheStorage接口,设定所有的缓存操作
public interface ICacheStorage
{
T Retrieve<T>(string key);
void Store(string key, object data);
void Remove(string key);
}
既然有一个新接口,就可以更新ProjectService类加入缓存的实现,构造注入
1 public class ProjectService
2 {
3 private IProjectRepository _projectRepository;
4 private ICacheStorage _cacheStorage;
5 public ProjectService(IProjectRepository iprojectRepository, ICacheStorage icacheStorage)
6 {
7 _projectRepository = iprojectRepository;
8 _cacheStorage = icacheStorage;
9 }
10
11 public IList<Project> GetProject(int id)
12 {
13 IList<Project> data = null;
14 string key = string.Format("project_{0}", id);
15 data = _cacheStorage.Retrieve<List<Project>>(key);
16 if (data == null)
17 {
18 data = _projectRepository.GetAllProject(0);
19 }
20
21 return data;
22 }
23 }
有时候我们看到的直接是 data = (IList<Project>)HttpContext.Current.Cache.Get(key); 替换15行的代码,这写法没毛病,只不过当有一天,如果要求换一种缓存实现方式时,就需要改动到ProjectService类中的这行代码,不符合开闭原则。现在ProjectService类中包含抽象的缓存对象,但是在这个类里面不需要依赖引用任何缓存组件或者具体的实现,如上图,我们需要定义一个适配器
public class HttpContextCacheAdapter : ICacheStorage
{
public T Retrieve<T>(string key)
{
T item = default(T);
try
{
item=(T)HttpContext.Current.Cache.Get(key);
}
catch (Exception)
{
}
return item;
}
public void Store(string key, object data)
{
HttpContext.Current.Cache.Insert(key, data);
}
public void Remove(string key)
{
HttpContext.Current.Cache.Remove(key);
}
}
用HttpContextCacheAdapter 类来实现 ICacheStorage接口中的方法,添加System.Web.Caching的引用,现在可以很轻松的实现一个新的缓存解决方案。
如果想扩展其他的缓存方案,现在只需要创建一个新的适配器,让ProjectService类与适配器通过共用的接口交互即可。
优点:
1、让具有不兼容接口的类在一起工作
2、通过引入适配器,可以复用现有的类,而不需要修改源代码,将目标类和适配者解耦合,解决了接口和复用环境不一致的情况很好的符合开闭原则
缺点:
1、一旦适配器多继承,会让代码的耦合度变高
2、匹配一个类和他的子类的情况不适用
使用情景:
1、复用环境与接口不符:系统要复用现有的类,现有类的接口不符合系统的接口
2、两个类功能类似,但是接口不同
3、双方都不太容易修改:第三方组件组件的接口,与系统接口不符