During business formulation, cache design is rarely introduced. After all, when indicators are unclear, This is a transitional design. after all, there are many ways to cache data. In many cases, it is very profitable to cache a page directly on the web. cache is a horizontal data processing application. Generally, AOP is introduced in the design. Application Components of ICO can be added in later stages. however, the introduction of AOP and ICO without much experience will directly increase the complexity and risks of applications. the design mainly introduces a simple design method to reference Cache during the design phase, but it does not bring complicated work costs.
A simple example
public class BlogService:Interfaces.IBlogService { public IList<Blog> List(string category, int size, int index, out int pages) { Expression exp = new Expression(); if (!string.IsNullOrEmpty(category)) exp &= Blog.iD == BlogLinkCategory.blog[BlogLinkCategory.category == category]; int count = exp.Count<Blog>(); pages = count / size; if (count % size > 0) pages++; return exp.List<Blog>(new Region(index, size), Blog.createTime.Desc); } public IList<BlogCategory> ListCategories() { return new Expression().List<BlogCategory>(); } public Blog Get(string id) { return (Blog.iD == id).ListFirst<Blog>(); }}
The above is a situation where cache applications are not considered at all. This is generally done in the early stage. After all, the primary problem is to complete the function.
Simply add Cache
The following uses the list method as an example to add cache processing methods.
public IList<Blog> List(string category, int size, int index, out int pages) { IList<Blog> result = redis.Get<IList<Blog>>("key"); if (result == null) { Expression exp = new Expression(); if (!string.IsNullOrEmpty(category)) exp &= Blog.iD == BlogLinkCategory.blog[BlogLinkCategory.category == category]; int count = exp.Count<Blog>(); pages = count / size; if (count % size > 0) pages++; result = exp.List<Blog>(new Region(index, size), Blog.createTime.Desc); redis.Set("key", result); } return result; }
This usually shows a comparison method in development. To be honest, it is indeed a great increase in workload to consider this at the beginning, especially when there is no performance requirement in the early stage, this will only increase the work and delay progress. in addition, the coupling of cache products cannot reach a better level. After all, developers need to learn the APIs of specific cache products.
Cache implementation
A simple slow storage access interface can be developed during the design.
public interface ICached { T Get<T>(string key); void Set(string key, object data); }
Introduce to interface definition during design
public interface IBlogService { IList<Blog> List(string category, int size, int index, out int pages); Blog Get(string id); Blog Save(string id, string title, string keywords, string data, params string[] categories); IList<BlogCategory> ListCategories(); ICached Cached { get; set; } }
This is a simple cached application specification for the logic layer. this greatly reduces developers' dependence on Cache products. Of course, this interface is poorly designed and may require timeout settings. although the goal of the solution is achieved, the ease of use is still relatively troublesome, and the work is not much reduced.
Simplified cache applications
In fact, the interface defines some simple delegate parameters for get, which can be a simple cache recurrence during application.
public interface ICached { T Get<T>(Func<T> handler, string key); void Set(string key, object data); }
It is easier to write the logic.
{ public IList<Blog> List(string category, int size, int index, out int pages) { dynamic eo = Cached.Get<dynamic>(() => { dynamic result = new ExpandoObject(); Expression exp = new Expression(); if (!string.IsNullOrEmpty(category)) exp &= Blog.iD == BlogLinkCategory.blog[BlogLinkCategory.category == category]; int count = exp.Count<Blog>(); result.Pages = count / size; if (count % size > 0) result.Pages++; result.Blogs = exp.List<Blog>(new Region(index, size), Blog.createTime.Desc); return result; }, key); pages = eo.Pages; return eo.Blogs; }
In fact, the principle is relatively simple, that is, the get internal implementation directly executes the func <t> method to get the data if the related key does not exist, and sets it to the cache. the preceding conditions and paging results are complicated. generally, the code is simple.
public TextBlock GetByTitle(string title) { return Cached.Get<TextBlock>(() => (TextBlock.iD == title).ListFirst<TextBlock>(),title); }
If you have to worry about it, you can do that.
public User Get(string name) { return (User.name == name).ListFirst<User>(); } public User Get(string name) { return Cached[name].Get<User>(() => { return (User.name == name).ListFirst<User>(); }); }
In this way, a layer of cached application code is built on the outside, and the code in it does not need to be modified.
Summary
By referencing cache at the logic layer or other layers, this design will not significantly change the complexity of the entire Code. At the beginning, you can reference an icached implementation that is not completely done. change the Code directly if necessary later. the icached design in this article is simple. After all, it is only used to reflect this design pattern. if the business field is complex, the behavior parameters reflected by icached may be more complex. however, developers always have a way to make complex calls simple.
Business logic layer cache should be designed