Are you good at using anonymous functions?

Source: Internet
Author: User

Try to get data from the cache. If the data exists, return. Otherwise, get the data from the data source, put it in the cache, and then return.

Are you familiar with the above logic description? If your application uses a large number of caches, the above logic may appear many times. For example:

Cachemanager Cachemanager =New Cachemanager();
 
Public List<User> Getfriends (IntUserid)
{
StringCachekey ="Friends_of_user _"+ Userid;
 
ObjectObjresult = cachemanager. Get (cachekey );
If(Objresult! =Null)Return(List<User>) Objresult;
 
List<User> Result =New Userservice(). Getfriends (userid );
Cachemanager. Set (cachekey, result );
 
ReturnResult;
}

This logic seems simple, but in actual applications, retrieving data from the data source may not simply call a method, but require collaboration between multiple classes and transaction control, the cache read/write may be more complex than the preceding example. Therefore, a readable approach is to provide three independent methods (read cache, read data sources, write cache ), to make a method with a cache, you only need to simply implement the read/write logic mentioned above.

AsArticleIf your application uses a large number of caches, the above logic may appear many times. To a certain extent, such duplication is redundant and violates the dry principle. Therefore, we try to provide a base class to encapsulate the cache read/write logic:

Public Abstract Class Cachereader<T>
{
/// <Summary> Get data from Cache </Summary>
/// <Param name = "data"> Data obtained from the cache </Param>
/// <Returns> Returns true if data is successfully obtained from the cache; otherwise, false. </Returns>
Public Abstract BoolGetfromcache (OutT data );
 
/// <Summary> Obtain data from the data source </Summary>
/// <Returns> Objects obtained from the data source </Returns>
Public AbstractT readfromsource ();
 
/// <Summary> Write Data to cache </Summary>
/// <Param name = "data"> Data to be written into the cache </Param>
Public Abstract VoidSettocache (t data );
 
PublicT read ()
{
T data;
If(This. Getfromcache (OutData ))ReturnData;
 
Data =This. Readfromsource ();
This. Settocache (data );
 
ReturnData;
}
}

Therefore, the cache read/write logic is concentrated in the read method of the cachereader class. For each cache read/write operation, we only need to implement a subclass of the cachereader class and provide the specific implementation of three abstract methods. As follows:

Private Class Getfriendcachereader:Cachereader<List<User>
{
Private IntM_userid;
Private StringM_cachekey;
Private CachemanagerM_cachemanager;
 
PublicGetfriendcachereader (IntUserid,CachemanagerCachemanager)
{
This. M_userid = userid;
This. M_cachekey ="Friends_of_user _"+ Userid;
This. M_cachemanager = cachemanager;
}
 
Public Override BoolGetfromcache (Out List<User> Data)
{
ObjectObjdata =This. M_cachemanager.get (This. M_cachekey );
If(Objdata =Null)
{
Data =Null;
Return False;
}
 
Data = (List<User>) Objdata;
Return True;
}
 
Public Override List<User> Readfromsource ()
{
Return New Userservice(). Getfriends (This. M_userid );
}
 
Public Override VoidSettocache (List<User> Data)
{
This. M_cachemanager.set (This. M_cachekey, data );
}
}

Therefore, the getfriends method can be modified as follows:

Public List<User> Getfriends (IntUserid)
{
Return New Getfriendcachereader(Userid, cachemanager). Read ();
}

The typical application of the "template method" mode is ...... Elegance? This is an obvious "overhead "! A getfriends method needs to develop a class, and hundreds or even hundreds of such methods are rarely used in applications? Therefore, we have developed hundreds of cachereader subclasses. each subclass needs to encapsulate all the objects and data used and implement three abstract methods-OMG, it can be said that "Oop" has reached its extreme!

Fortunately, we can use the anonymous method. To this end, we write a helper method:

Public Static Class Cachehelper
{
Public Delegate Bool Cachegetter<Tdata> (OutTdata );
 
Public StaticTdata get <tdata> (
Cachegetter<Tdata> cachegetter,
Func<Tdata> sourcegetter,
Action<Tdata> cachesetter)
{
Tdata data;
If(Cachegetter (OutData ))
{
ReturnData;
}
 
Data = sourcegetter ();
Cachesetter (data );
 
ReturnData;
}
}

Delegation is a good thing and can be used as a method parameter. The existence of anonymous methods makes this method particularly useful. For example, we can:

Public List<User> Getfriends (IntUserid)
{
StringCachekey ="Friends_of_user _"+ Userid;
 
Return Cachehelper. Get (
Delegate(Out List<User> Data)// Cache Getter
{
ObjectObjdata = cachemanager. Get (cachekey );
Data = (objdata =Null)?Null:(List<User>) Objdata;
 
ReturnObjdata! =Null;
},
() =>// Source Getter
{
Return New Userservice(). Getfriends (userid );
},
(Data) =>// Cache setter
{
Cachemanager. Set (cachekey, data );
});
 
}

Does it look weird? In fact, it's good to get used to it. This method has many advantages:

    • Good Readability: The operation logic is divided into different blocks.
    • Easy programming: You can directly use the parameters and external objects of the method without the hassle of encapsulation.
    • Easy debugging: After the breakpoint is set, you can easily see the process of "reading from the cache", "reading from the data source", and "writing to the cache.

After the emergence of anonymous methods, this method of passing the delegate as a parameter is very common. For example, the same calling method can be used in the parallel Library launched by Microsoft:

Void Parallelcalculate ()
{
DoubleResult = 0;
ObjectSyncobj =New Object();
 
List<Int> List = getintlist ();
 
Parallel. For <Double> (
0,
List. Count,
() => 0,
(Index, PS) =>
{
IntValue = list [Index];
For(IntN = 0; n <100; n ++)
{
PS. threadlocalstate + =Math. SQRT (value )*Math. Sin (value );
}
},
(Threadresult) =>
{
Lock(Syncobj)
{
Result + = threadresult;
}
});
 
Console. Writeline ("Result ="+ Result );
}

Have you accepted this practice?

Are you good at using anonymous functions?

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.