适配器模式(结构型)

定义:

将一个类的接口转换成客户希望的另一个接口, 使得原本由于接口不兼容不能再一起工作的类,可以在一起工作

假设场景:

  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、双方都不太容易修改:第三方组件组件的接口,与系统接口不符 

 
 
 

 

posted @ 2018-06-12 17:20  风吹一点云  阅读(405)  评论(0编辑  收藏  举报