项目架构开发:数据访问层之Cache

数据访问层简单介绍

数据访问层,提供整个项目的数据访问与持久化功能。在分层系统中所有有关数据访问、检索、持久化的任务,最终都将在这一层完成。

来看一个比较经典的数据访问层结构图

大概可以看出如下信息

1、有缓存、日志、异常处理、数据CRUD、查询及数据事务等功能

2、无缝对接如EF、ADO.NET、NH、Dapper等数据访问技术

3、对外只开放接口层,隐藏具体实现,这样就可以解耦业务层与数据访问层

 

今天斗胆通过一个简单实例来实践一下,如有不妥的地方,欢迎指正

创建接口层,定义可以提供的一些服务接口

 

这里我们一个有5种服务接口,方法的功能就不介绍了,应该都能看懂

缓存接口:ICache.cs

1     public interface ICache<T> where T : class
2     {
3         IEnumerable<T> Gets(string key);
4         T Get(string key);
5         bool Sets(string key, IEnumerable<T> value, TimeSpan expiresIn);
6         bool Set(string key, T value, TimeSpan expiresIn);
7         bool Remove(string key);
8     }

 

缓存服务的实现

因为可能支持多种缓存,所以我实现了Web缓存与Redis缓存,这2中缓存分别在项目初期和后期集群中可能会用到

 

我们来看HttpRuntimeCache.cs (还有一种Web缓存HttpContext.Cache,不够这种只能在Web应用使用,所以一般不推荐)

 1 public class HttpRuntimeCache<T> : ICache<T> where T : class
 2     {
 3         public HttpRuntimeCache()
 4         {
 5 
 6         }
 7 
 8         public T Get(string key)
 9         {
10             if (System.Web.HttpRuntime.Cache[key] == null)
11             {
12                 return default(T);
13             }
14 
15             return System.Web.HttpRuntime.Cache[key] as T;
16         }
17 
18         public bool Set(string key, T value, TimeSpan expiresIn)
19         {
20             Set(key, value, expiresIn.Seconds);
21             return true;
22         }
23 
24         public bool Remove(string key)
25         {
26             System.Web.HttpRuntime.Cache.Remove(key);
27             return true;
28         }
29 
30         private void Set(string key, object value, int absoluteSeconds)
31         {
32             System.Web.HttpRuntime.Cache.Insert(key, value, null, DateTime.Now.AddSeconds(absoluteSeconds), TimeSpan.FromSeconds(0));
33         }
34     }

 

现在缓存功能已经实现了;大家应该很容易想到怎麼使用了,比如在业务层这样使用

1 ICache<User>  cache = new HttpRuntimeCache<User>();
2 var user = cache.Get("key");

 

其实这样是不对的,因为这样的话接口ICache相当于没什么用处,没有起到应有的作用(隔离具体实现)

如果要换另一种缓存实现(比如redis),那还要在所有使用了 new HttpRuntimeCache<User>() 的地方改正过来

这样的耦合要去掉;有2种方式,通过IOC在实例化的时候依赖注入;另一种就是新建一个基础设施层,业务层依赖于这一层

因为业务层肯定是需要调用一些Utilities、Helper等类型的工具类,这个应该是躲不掉的,再怎么接口隔离也去除不了这点

 

基础设施层的实现

 

Cache.cs 

 1     public sealed class Cache<T> where T : class
 2     {
 3         private readonly static ICache<T> cacheProvider;
 4 
 5         static Cache()
 6         {
 7             cacheProvider = ProviderHelper<T>.GetCacheProvider();
 8         }
 9 
10         public static IEnumerable<T> Gets(string key)
11         {
12             return cacheProvider.Gets(key);
13         }
14 
15         public static T Get(string key)
16         {
17             return cacheProvider.Get(key);
18         }
19 
20         public static bool Sets(string key, IEnumerable<T> value, TimeSpan expiresIn)
21         {
22             return cacheProvider.Sets(key, value, expiresIn);
23         }
24 
25         public static bool Set(string key, T value, TimeSpan expiresIn)
26         {
27             return cacheProvider.Set(key, value, expiresIn);
28         }
29 
30         public static bool Remove(string key)
31         {
32             return cacheProvider.Remove(key);
33         }
34     }

 

 ProviderHelper.cs 实现如下图

 

至此,缓存功能实现完毕,我们新建一个测试项目看看结果

 1     [TestClass]
 2     public class CacheTest
 3     {
 4         [TestMethod]
 5         public void Set()
 6         {
 7             var user = new LoginUser()
 8             {
 9                 Id = Guid.NewGuid(), 
10                 LoginName = "LoginName",
11                 IsEnabled = 1,
12                 Password = "mima1987",
13                 CreateTime = DateTime.Now
14             };
15 
16             Cache<LoginUser>.Set("UnitTest3.TestMethod1", user, TimeSpan.FromSeconds(10));
17             var user2 = Cache<LoginUser>.Get("UnitTest3.TestMethod1");
18 
19             Assert.AreEqual(user.Id, user2.Id);
20         }
21     }

 

看来没有什么问题。

 

项目架构开发系列

 

posted @ 2017-03-04 18:49 蓝建荣 阅读(...) 评论(...) 编辑 收藏