Implementation of the fine-grained Singleton Mode

Source: Internet
Author: User

Background Discussion

As a typical design pattern, the Singleton pattern is often used to demonstrate the skills of the design pattern ,. both the Net Language and Java have improved the singleton mode defined in the classic design patterns: Elements of reusable object-oriented software, for example, C # can implement the singleton mode of thread security in a process in a very simple but perfect way.

C # Implementation of the most classic Singleton mode (lazy constructor)

Public class Singleton <br/>{< br/> Private Static Singleton instance; // unique instance <br/> protected Singleton () {}// directly instantiate the closed Client Program <br/> Public static Singleton instance <br/>{< br/> Get <br/>{< br/> If (Instance = NULL) <br/> instance = new Singleton (); <br/> return instance; <br/>}< br/>}

C # Singleton mode of relative thread security implemented through double check

Public class Singleton <br/>{< br/> protected Singleton () {}< br/> Private Static volatile Singleton instance = NULL; <br/> // process of creating a unique instance in lazy mode <br/> Public static Singleton instance () <br/>{< br/> If (instance = NULL) // outer If <br/> lock (typeof (Singleton) // synchronize shared resources in multiple threads <br/> If (instance = NULL) // inner layer if <br/> instance = new Singleton (); <br/> return instance; <br/>}< br/>}

C # indirect Singleton mode based on language features

Class Singleton <br/>{< br/> private Singleton () {}< br/> Public static readonly Singleton instance = new Singleton (); <br/>}

 

However, in a project, we often need a more coarse or fine-grained singleton. For example, a thread is a background task that runs for a long time. It has many modules and intermediate processing, however, each thread wants to have its own singleton object in the thread, and other threads also operate on Singleton in its own thread independently, the so-called line-level Singleton actually has a total number of instances = 1 (the only one in each thread) * n (number of threads) = n.

By marking static members as system. threadstaticattribute, the. NET program ensures that the value of the static field is unique for each thread. But this is very effective for the Windows form program, for web form, Asp. net web service and other web applications are not applicable because they are executed in the same IIS thread and the objects passed during client calls are shared in httpcontext, that is to say, it cannot simply use system. threadstaticattribute implementation. Moreover, using system. threadstaticattribute cannot easily use the preceding content as follows:

[Threadstatic] <br/> Public static readonly Singleton instance = new Singleton ();

According to the. NET design requirements, do not specify the initial value for the field marked as it, because such initialization only happens once, so only one thread will be affected when the class constructor is executed. If the initial value is not specified, it depends on the field whose Initialization is its default value. If it is of the reference type, it can be dependent on the field whose Initialization is null. That is to say, in the case of multithreading, except for the first instance, other threads expect to obtain a unique instance in this way, but the result is actually a null and cannot be used.

Solve the issue of fine-grained Singleton in Windows form

For Windows Forms, you can use system. threadstaticattribute high-speed CLR the static and unique attribute instance is only static within the thread, but the trouble is how to construct it, as described in the Background section above, you cannot put it in the static constructor of the entire class or initialize it directly. What should you do? Fortunately, if the cool implementation is not applicable here, we will return to the lazy method in the most classic mode to load the singleton instance. Do you think this thread is not safe? The implementation method is indeed not thread-safe, but the singleton structure itself is already running in a thread, in this unsafe way, only Singleton objects within the "One MU, three sub-Locations" Scope of the thread are implemented, but the objects are safe. The new implementation is as follows:

Public class Singleton <br/>{< br/> private Singleton () {}< br/> [threadstatic] // It indicates that each instance is static only in the current thread <br/> Private Static Singleton instance; <br/> Public static Singleton instance <br/> {<br/> Get <br/> {<br/> If (instance = NULL) <br/> instance = new Singleton (); <br/> return instance; <br/>}< br/>}

Unit Test

/// Define the target object to be executed by each thread <br/> /// check whether Singleton exists in the thread. <br/> class work <br/> {<br/> Public static ilist log = new list (); <br/> // execution definition of each thread <br/> Public void procedure () <br/>{< br/> Singleton S1 = Singleton. instance; <br/> Singleton S2 = Singleton. instance; <br/> // indicates that the instance can be constructed properly <br/> assert. isnotnull (S1); <br/> assert. isnotnull (S2); <br/> // verify whether the two internal references of the current thread executor are the same instance <br/> assert. areequal (s1.gethashcode (), s2.gethashcode (); <br/> // register the singleton object ID used by the current thread <br/> log. add (s1.gethashcode ()); <br/>}< br/> [testclass] <br/> public class testsingleton <br/>{< br/> private const int threadcount = 3; <br/> [testmethod] <br/> Public void test () <br/>{< br/> // create a certain number of thread execution bodies <br/> thread [] threads = new thread [threadcount]; <br/> for (INT I = 0; I <threadcount; I ++) <br/> {<br/> threadstart work = new threadstart (new work ()). procedure); <br/> threads [I] = new thread (work ); <br/>}< br/> // execution thread <br/> foreach (thread in threads) thread. start (); <br/> // terminate the thread and perform other cleanup operations <br/> //...... <br/> // determine whether the singleton instances in different threads are different <br/> for (INT I = 0; I <threadcount-1; I ++) <br/> for (Int J = I + 1; j <threadcount; j ++) <br/> assert. arenotequal (work. log [I], work. log [J]); <br/>}< br/>}

The following is an analysis of the unit test code description:

* In the work. Procedure () method, the instance static attribute of the singleton class is called twice. It is verified to be the same Singleton class instance. At the same time, because the constructor of the singleton class is defined as private, the thread (Client Program) cannot instantiate the singleton class by itself, so it also meets the design intent of this pattern;

* By registering and checking Singleton instances used inside each thread, it is confirmed that different threads actually have reference to different instances, so the Fine Granularity (line level) that we need to implement is met) intention;

* Solves the issue of fine-grained Singleton in web form.

Although the preceding threadstatic method solves the problem of Windows form, it is not applicable to web form applications because the local global region of each session in the web form application is not a thread, but its own httpcontext, therefore, the corresponding Singleton instance should also be saved in this location. In implementation, we only need to make a few modifications to complete the fine-grained Singleton design under a web form:

Note: The Web form applications include ASP. NET application and ASP. NET web
Service, ASP. NET Ajax, and other related applications. However, the examples are not in. NET Compact framework and. Net micro
The framework environment has been verified.

Public class Singleton <br/>{< br/> // a complex key value, used to distinguish it from other content in httpcontext <br/> private const string key = "just. complicated .. singleton "; <br/> private Singleton () {}< br/> Public static Singleton instance <br/>{< br/> Get <br/>{< br/> // lazy instantiation process based on httpcontext <br/> Singleton instance = (Singleton) httpcontext. current. items [Key]; <br/> If (instance = NULL) <br/>{< br/> instance = new Singleton (); <br/> httpcontext. current. items [Key] = instance; <br/>}< br/> return instance; <br/>}< br/>}

Unit Test

Using system; <br/> using system. web; <br/> using marvellousworks. practicalpattern. singletonpattern. webcontext; <br/> using Microsoft. visual Studio. testtools. unittesting; <br/> namespace singletonpattern. test. web <br/> {<br/> Public partial class _ default: system. web. UI. page <br/> {<br/> protected void page_load (Object sender, eventargs e) <br/>{< br/> Singleton S1 = Singleton. instance; <br/> Singleton S2 = Singleton. instance; <br/> // confirm that the singleton instance reference has been instantiated. <br/> assert. isnotnull (S1); <br/> assert. isnotnull (S2); <br/> // confirm that the two references call the same Singleton instance. <br/> assert. areequal (s1.gethashcode (), s2.gethashcode (); <br/> // displays the ID of the current Singleton instance, it is used to compare Singleton instances with other <br/> // Singleton instances in the httpcontext environment. <br/> instancehashcode. TEXT = s1.gethashcode (). tostring (); <br/>}< br/>}

Same as above, this unit test demonstrates the fine-grained Singleton in web form. By migrating the storage location of a unique instance from the current thread to httpcontext, the fine-grained Singleton design intent can be achieved.
More general and fine-grained Singleton

However, if you are a designer of a public library or a public platform, it is hard to predict that your class library will run in Windows form or web form, but the singleton mode serves as a lot of public mechanisms, the most commonly used technology tools, clocks, and so on will often become the basis of other class libraries. Especially when it comes to business logic, it is difficult to define a dead-running mode during the development process. What should I do?

Here, we use a tool class to determine whether the current execution environment is web form or Windows form, and then create a 2 in 1 fine-grained Singleton (which sounds a bit like a Nintendo game card in the early years ), however, just like the single responsibility principle of object-oriented design, bringing two together produces some ugly redundant code, however, Singleton differs significantly from other design patterns-he does not want to be instantiated by external mechanisms because he wants to maintain the uniqueness of the instance, therefore, some common dependency inversion techniques are not suitable here. Here we implement a slightly redundant web form + windows Form 2 in 1 fine-grained Singleton as follows:

C # tool class genericcontext

/// Determine whether the current application is a Web application's helper method (unofficial method) <br/> Private Static bool checkwhetherisweb () <br/>{< br/> bool result = false; <br/> appdomain domain = appdomain. currentdomain; <br/> try <br/> {<br/> If (domain. shadowcopyfiles) <br/> result = (httpcontext. current. getType ()! = NULL); <br/>}< br/> catch (system. Exception) {}< br/> return result; <br/>}

Implementation of the fine-grained Singleton mode of C # 2in 1

Using system; <br/> using system. web; <br/> using marvellousworks. practicalpattern. common; <br/> namespace marvellousworks. practicalpattern. singletonpattern. combined <br/>{< br/> public class Singleton <br/>{< br/> private const string key = "marvellousworks. practical. singleton "; <br/> private Singleton () {}// external closed structure <br/> [threadstatic] <br/> Private Static Singleton instance; <br/> Public static Singleton instance <br/> {<br/> Get <br/> {<br/> // use the unofficial methods of the previously prepared genericcontext <br />/// determine whether the current execution mode is web form or non-web form <br/> // This method is not in. <br/> If (genericcontext. checkwhetherisweb () // web form <br/>{< br/> // lazy instantiation process based on httpcontext <br/> Singleton instance = (Singleton) httpcontext. current. items [Key]; <br/> If (instance = NULL) <br/>{< br/> instance = new Singleton (); <br/> httpcontext. current. items [Key] = instance; <br/>}< br/> return instance; <br/>}< br/> else // non-web form mode <br/>{< br/> If (instance = NULL) <br/> instance = new Singleton (); <br/> return instance; <br/>}< br/>}

Summary

In the design pattern, many intent-specific expressions also have a semantic scope, such as "unique", "all related", and "a series of interdependent, however, projects often have their own customization requirements. If possible, we recommend that you use the features of the language and language runtime environment to complete these tasks.

Note: Reprinted from: http://www.infoq.com/cn/articles/fine-grained-singleton-pattern

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.