A brief discussion on single case design pattern _java in Java programming

Source: Internet
Author: User

Write software often need to use the Print log function, can help you debug and positioning problems, the project online can also help you analyze the data. But Java native System.out.println () methods are rarely used in real project development, and even code-checking tools such as findbugs think that using System.out.println () is a bug.

Why is System.out.println (), a novice artifact of Java, being spurned in real project development? In fact, as long as the careful analysis, you will find many of its drawbacks. such as uncontrollable, all logs will be printed as usual after the project is online, to reduce operational efficiency; Or you cannot log to a local file, and once the print is cleared, the log will never be able to find it again, or if the printed content is not tagged, you will find it difficult to tell which class the log is printed in.

Your leader is also not a fool, with System.out.println () all the drawbacks he also clearly, so he gave you the task today is to create a log tool class, to provide better logging capabilities. But your leader is not bad, and does not allow you to start with a function of the great Log tool class, only need to control the printing level log tool.

This requirement is not difficult for you, you immediately began to write, and soon completed the first version:

  public class Logutil {public 
    final int DEBUG = 0; 
   
    public final int INFO = 1; 
   
    public final int ERROR = 2; 
   
    public final int nothing = 3; 
   
    public int level = DEBUG; 
   
    public void Debug (String msg) { 
      if (debug >= level) { 
        System.out.println (msg); 
      } 
    } 
   
    public void info (String msg) { 
      if (info >= level) { 
        System.out.println (msg); 
      } 
    } 
   
    public void error (String msg) { 
      if (Error >= level) { 
        System.out.println (msg); 
      } 
    } 
  } 



This class is used to print the log, and you can control the printed content freely by simply controlling level levels. For example, now that the project is in the development phase, the level is set to debug so that all log information will be printed. And the project if the line, you can set the level to info, so you can only see the info and above the log printing. If you only want to see the error log, you can set the level as error. And if you develop a project that is a client version and you don't want any log to print, you can set the level to nothing. When printing, you only need to call:

  New Logutil (). Debug ("Hello world!"); 



You can not wait to introduce this tool to your leader, your leader after listening to your introduction, said: "Good, the future everyone will use you write this tool to print the log!" ”

But not long after, your leader find you to feedback the question. He said that although this tool is easy to use, but the printing of this kind of thing is not a distinction between objects, here every time need to print a log of the need for a new logutil, too much memory, I hope you can change this tool into a single example mode.

You think your leader is making a lot of sense, and you're also trying to take this opportunity to practice using design patterns, so you write the following code (PS: This is my own implementation of the code, and I did not pay attention to thread synchronization problem):

 public class Logutil {private static logutil logutilinstance; 
   
    public final int DEBUG = 0; 
   
    public final int INFO = 1; 
   
    public final int ERROR = 2; 
   
    public final int nothing = 3; 
   
    public int level = DEBUG; 
        Private Logutil () {} public static Logutil getinstance () {if (logutilinstance = = null) { 
      Logutilinstance = new Logutil (); 
    return logutilinstance; 
      public void Debug (String msg) {if (debug >= level) {System.out.println (msg); 
      } public void info (String msg) {if (info >= level) {System.out.println (msg); 
      } public void Error (String msg) {if (Error >= level) {System.out.println (msg); 
    } public static void Main (string[] args) {logutil.getinstance (). Debug ("Hello world!"); } 
  } 


The Logutil constructor is privatized first, so that you cannot use the New keyword to create an instance of Logutil. A slogutil private static variable is then used to save the instance, and a public getinstance method is provided to obtain an instance of the Logutil, in which it is judged that if the slogutil is null, a new Logutil instance is created. Otherwise, return directly to Slogutil. This ensures that only one logutil instance is present in memory. Single Case mode completed! The code for the print log needs to be changed to the following ways:

  Logutil.getinstance (). Debug ("Hello World");  


You will show this version to your leader look, he smiled after looking, said: "Although this seems to have achieved a single case mode, but there are bugs oh."
Are you skeptical that the single case pattern is not always the way it is? What other bugs will there be?

Your leader prompts you to use the singleton mode in order for this class to have only one instance in memory, but have you considered printing the log in multiple threads? As shown in the following code:

  public static Logutil getinstance () { 
    if (logutilinstance = null) { 
      logutilinstance = new Logutil (); 
    } 
   
    return logutilinstance; 
  } 


If there are now two threads executing the getinstance method at the same time, the first thread has just finished line 2nd and has not executed line 3rd, at which point the second thread executes to line 2nd, which finds slogutil or null, and enters the If judgment. This way your singleton pattern fails because two different instances are created.
You realize, but your mind is very fast, immediately think of the solution, just to add a synchronous lock to the method can be, the code is as follows:

  Public synchronized static Logutil getinstance () { 
    if (logutilinstance = = null) { 
      logutilinstance = new Logutil (); 
    } 
   
    return logutilinstance; 
  } 


In this way, only one thread at a time is allowed to execute code inside the getinstance, which effectively solves the scenario where two instances are created.
Your leader read your new code and said, "Well, yes." This does solve the possibility of creating two instances, but the code is still problematic. ”

You are nervous, how can there be problems ah?

Your leader smile: "Don't be nervous, this is not a bug, but the performance can optimize some." You see, if you add a synchronized to the GetInstance method, I will be affected by the sync lock every time I go to execute the Getinstace method, which will reduce the efficiency of the operation. In fact, you just need to add a sync lock for the first time you create a logutil instance. I'll teach you how to optimize it better. ”

First, remove the Synchronized keyword from the method declaration and add it to the method body:

  public static Logutil getinstance () { 
    if (logutilinstance = null) { 
      synchronized (logutil.class) { 
        if (Logut Ilinstance = = null) { 
          //is required here, because it is possible to execute both processes before synchronized 
          logutilinstance = new Logutil () 
        ; 
      } 
    } return 
   
    logutilinstance; 
  } 


After the code is changed, the only way to get to line 3rd is when the Slogutil is not initialized, and then add the sync Lock. Wait Slogutil One but initialization completes, can not go to 3rd line again, such execution getinstance method also will not be affected by the synchronization lock again, the efficiency will have certain promotion.
You can't help admiring that the method is so ingenious that it is too clever to think of it.

Your leader immediately humble up: "This method is called double lock (double-check locking), not I think out of, more information you can check on the Internet." ”

In fact, in Java to implement a single example I am more accustomed to using a hungry man mode

The lazy type is characterized by delayed loading, which is not loaded until it is used

The feature of the A hungry man is that it is loaded at the beginning, so it can be returned directly each time it is used (I recommend this one because there is no need to consider too many thread safety issues, and of course the lazy type can solve the synchronization problem through the dual locking mentioned above)

The code for implementing logging in a Hungry man is as follows:

  public class Logutil { 
    private static final Logutil logutilinstance = new Logutil (); 
   
    public final int DEBUG = 0; 
   
    public final int INFO = 1; 
   
    public final int ERROR = 2; 
   
    public final int nothing = 3; 
   
    public int level = DEBUG; 
   
    Private Logutil () { 
   
    } public 
   
    static Logutil getinstance () {return 
      logutilinstance; 
    } 
   
    public void Debug (String msg) { 
      if (debug >= level) { 
        System.out.println (msg); 
      } 
    } 
   
    public void info (String msg) { 
      if (info >= level) { 
        System.out.println (msg); 
      } 
    } 
   
    public void error (String msg) { 
      if (Error >= level) { 
        System.out.println (msg); 
      } 
    } 
   
    public static void Main (string[] args) { 
      logutil.getinstance (). Debug ("Hello world!"); 
    } 
   


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.