当前位置:网站首页>Common singleton mode & simple factory

Common singleton mode & simple factory

2022-06-24 14:16:00 Yilin YL

Catalog

Preface :

The singleton pattern :

One , Starving model

Two , The sluggard model

1. Simple method of one-way judgment

2. Double check lock method

3. Instantiate this class through a static inner class

4. Enumeration method :

Factory mode

1. The concept of factory pattern :

2. Usage scenario of factory mode :

3. Factory method :


Preface :

Why should we learn design patterns : Design patterns (disign pattern) Represents best practice , It is the experience of many excellent software developers , It is a solution to a specific problem . It is not a grammatical rule , And don't stick to a particular language . Proper use of design patterns can make code more reusable 、 Maintainability 、 Extensibility 、 Robustness and security , These are very important non functional requirements of the system .

First, let's briefly analyze several common singleton patterns .

The singleton pattern :

1. The concept of singleton pattern : As the name suggests, only one instance will be used in memory .

2. The difference between the two singleton modes

The main difference between the two is Objects are created at different times Hungry man mode creates objects when classes are loaded , Lazy mode is created when it is used ( That is, the instance object method is created when it is called ).

② The second is the thread safety of both : Hungry man mode is a single thread mode , So there will be no thread safety issues . This is the problem with the lazy man model .

3. Advantages and disadvantages of singleton mode :

advantage :

  • There is only one object in memory , Save memory space ;
  • Avoid frequent creation of destroyed objects , Can improve performance ;
  • Avoid multiple use of shared resources , Simplify access ;
  • Provide a global access point for the whole system .

shortcoming :

  • Not for objects that change frequently ;
  • Abuse of single case will bring some negative problems , For example, in order to save resources, the database connection pool object is designed as a single instance class , May cause too many programs sharing connection pool objects to overflow connection pool ;

The singleton mode is divided into the following two types :

One , Starving model

Let's make it simple : Hungry man mode is to instantiate a singleton while defining it , It can be used directly . In other words, in the hungry man mode , stay SingletonDemo01 An instance of this class already exists in JVM It's in . In this way, it is easier to understand .

  The code is as follows :

package com.ljq.text;

/**
 *  The singleton pattern - Starving model 
 * @author  Yilin 
 *
 */
public class SingletonDemo01 {

	// 1.  You need to have a private constructor , Prevent this class from passing new To create an instance 
	private SingletonDemo01() {
	}

	// 2.  Hunger mode , First, generate an instance 
	private static final SingletonDemo01 instance = new SingletonDemo01();

	// 3.  Static methods , Used to get the generated instance 
	public static SingletonDemo01 getInstance() {
		return instance;
	}

	public String hello(String name) {
		return "hello " + name;
	}

	/**
	 *  Test whether multithreading is a safe method 
	 * 
	 * @param args
	 */
	public static void main(String[] args) {

		for (int i = 0; i < 100; i++) {
			new Thread(() -> {
				System.out.println(SingletonDemo01.getInstance().hashCode());
			}).start();
		}

		SingletonDemo01 s = SingletonDemo01.getInstance();
		String hello_world = s.hello("world");
		System.out.println(hello_world);
	}

}

Realization principle :

1️⃣ Privatize the constructor , To prevent this class from being new Form examples of

2️⃣ Create a static variable , This constant is new Out of this class , It is static because static attributes or methods belong to classes , It can better ensure the uniqueness of the singleton pattern .

3️⃣ Create a static method to return constants , That is, the generated instance

Here we also create a common method by the way hello Pass in a string Parameter is used to return hello Concatenate the string of this parameter to facilitate our test .

test :

1️⃣ This call 100 Threads call static methods through class names and then use hashcode Method to print out the final result .

2️⃣ Then the test calls the static method through the class name getInstance Get the instance class of this class and call hello How to print .

The console results are as follows :

  We'll find out , Use hashcode Method prints the same results .

Two , The sluggard model

The lazy man model has the possibility of wasting resources .

There are four main ways of starving Han mode :

1. Simple method of one-way judgment

This is actually a relatively simple lazy man mode , So the latter method is also changed on this .

The code is as follows :

package com.ljq.text;

import java.net.Socket;

/**
 *  The singleton pattern - Slacker type ( There are thread safety issues )
 * 
 * @author  Yilin 
 *
 */
public class SingletonDemo02 {

	private SingletonDemo02() {
		//  The running time of the simulation constructor 
		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	private static SingletonDemo02 singletonDemo02 = null;

	public static synchronized SingletonDemo02 getInstance() {

		if (singletonDemo02 == null) {

			singletonDemo02 = new SingletonDemo02();
		}

		return singletonDemo02;
	}

	public String hello(String name) {
		return "hello " + name;
	}

	/*
	 *  Test whether the multi-threaded singleton mode is safe 
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		

		for (int i = 0; i < 100; i++) {
			new Thread(() -> {
				System.out.println(SingletonDemo02.getInstance().hashCode());
			}).start();
		}
	}
}

Realization principle :

1️⃣ Privatize the constructor , The running time of the construction method is simulated in the construction method  .

2️⃣ Define a static variable and initialize it to null

3️⃣ Define the method to obtain the instance class and apply the synchronization lock , Add judgment to the method body , If the static constant is null Value is assigned to it

We tested and found that :

Through the console results, the results of the 100 threads we traverse are consistent , But it's not like this , This method still has security problems , It just doesn't happen every time .

2. Double check lock method

Compare our one-way judgment method above , Although the lazy mode can realize the singleton under multithreading , But rough will getInstance() lock , Such a price is actually very high , Why? ?

because , Only when the first call getInstance() You need to create objects synchronously , Call again after creation getInstance() Yes, it simply returns the member variable , There is no need to synchronize , So there is no need to lock the whole method .

Because synchronizing a method reduces 100 Times or more performance , The overhead of acquiring or releasing locks per call can be avoided : Once the initialization is complete , It is unnecessary to obtain the release lock .

So there is a double check lock mode :

Double lock mode refers to further optimization based on lazy mode , Add... To the definition of static objects volatile lock To ensure the uniqueness of objects during initialization , When getting an object, use synchronized (Singleton.class) Lock the singleton class to ensure the uniqueness of the operation .

The code is as follows :

package com.ljq.text;

/**
 *  The singleton pattern - Slacker type ( Double judgmental , Thread safety , But the performance is lower )
 * 
 * @author  Yilin 
 *
 */
public class SingletonDemo03 {

	private SingletonDemo03() {
		//  The running time of the simulation constructor 
		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	private static SingletonDemo03 singletonDemo03 = null;

	public static SingletonDemo03 getInstance() {
		//  The system reduces the synchronization block to improve performance , Is that OK ?
		if (singletonDemo03 == null) {
			/// ....
			synchronized (SingletonDemo03.class) {
				if (singletonDemo03 == null) {
					singletonDemo03 = new SingletonDemo03();
				}
			}
		}
		return singletonDemo03;
	}

	public String hello(String name) {
		return "hello " + name;
	}

	/*
	 *  Test whether the multi-threaded singleton mode is safe 
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		for (int i = 0; i < 100; i++) {
			new Thread(() -> {
				System.out.println(SingletonDemo03.getInstance().hashCode());
			}).start();
		}
	}
}

  In fact, the whole process is also very clear and simple :

① Check if the variable is initialized ( Don't get the lock first ), If it has already been initialized, return this variable immediately

② Gets the lock

③ The second time, check whether the variable has been initialized : If another thread has ever acquired a lock , Then the variable has been initialized , Returns the initialized variable

④ otherwise , Initialize and return variables

So! , The reason for the second verification is to prevent re creation , If there is a situation , When singletonDemo03 When the thread has not been created T1 call getInstance(), Because of the first judgment singletonDemo03 ==null, The thread T1 Ready to continue , But because the resources are used by threads T2 Take over , here T2 call getInstance(), similarly , because singletonDemo03 There is no instantiation ,T2 You can also pass the first if, And then move on , Synchronization code block , the second if Also through , Then the thread T2 Created an instance singletonDemo03 . The thread T2 To complete the task , The resource returns to the thread T1,T1 This also enters the synchronization code block , Without this, the second if, that ,T1 It will also create a singletonDemo03 example , that , Multiple instances will be created , But add the second if, You can completely avoid the problem of multiple instances created by this multithreading .

3. Instantiate this class through a static inner class

The code is as follows :

package com.ljq.text;

/**
 *  The singleton pattern - Lazy loading ( Thread safety )
 * 
 * @author  Yilin 
 *
 */
public class SingletonDemo04 {

	//  Prevent external instantiation 
	private SingletonDemo04() {
		//  The simulation constructor takes time to run 
		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	static {

	}

	//  Use a static inner class to use a SingletonDemo04 object 
	private static class SingletonDemoHolder {
		private final static SingletonDemo04 instance = new SingletonDemo04();
	}

	public static SingletonDemo04 getInstance() {
		return SingletonDemoHolder.instance;
	}

	public String hello(String name) {
		return "hello " + name;
	}

	/*
	 *  Test whether the multi-threaded singleton mode is safe 
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		for (int i = 0; i < 100; i++) {
			new Thread(() -> {
				System.out.println(SingletonDemo04.getInstance().hashCode());
			}).start();
		}
		System.out.println(SingletonDemo04.getInstance());
	}
}

test result :

4. Enumeration method :

Enum The full name is enumeration, Chinese is commonly known as Enumeration class .

Speaking of enumerating classes , Have studied or understood C/C++ All of us should know something about him .

But in Java In the category of language , Is in JDK5 Was introduced in the version of .enum Is the keyword used to declare

The code is as follows :

package com.ljq.text;

/**
 *  The singleton pattern - Enumeration type 
 * @author  Yilin 
 *
 */
public enum SingletonDemo05 {

	INSTANCE;

	public String hello(String name) {
		return "hello " + name;
	}

	/*
	 *  Test whether the multi-threaded singleton mode is safe 
	 * 
	 * @param args
	 */
	public static void main(String[] args) {

		for (int i = 0; i < 100; i++) {
			new Thread(() -> {
				System.out.println(SingletonDemo05.INSTANCE.hashCode());
			}).start();
		}
	}
}

Factory mode

1. The concept of factory pattern :

Methods or classes used to generate objects , Call it a factory . The singleton pattern mentioned above can also be regarded as a special factory .

2. Usage scenario of factory mode :

Why working mode is needed , The original use new The way is also very simple , And easy to understand ?

The reason for using the factory is that we can use the factory mode , To centrally control the creation process of objects , This can bring more flexibility to the design .

such as :spring Of IOC A container is a classic implementation of the factory pattern .

3. Factory method :

Used to produce the specified series of objects . Take the duck as an example , Ducks have real ducks , Rubber duck , Electronic toy duck, etc . How to easily create a variety of ducks , And control the creation process , To facilitate future maintenance and expansion ?

The diagram is as follows :

  We now have a duck shop :

package com.ljq.factory;

/**
 *  Duck's abstract class 
 * 
 * @author  Yilin 
 *
 */
public abstract class Duck {

	abstract public void quack();
}

There are four kinds of ducks in our store :

package com.ljq.factory;

/**
 * 
 * @author  Yilin 
 *
 */
public class PinkDuck extends Duck {

	
	@Override
	public void quack() {
		System.out.println(" I am a pink duck ");
	}

}
package com.ljq.factory;


/**
 * 
 * @author  Yilin 
 *
 */
public class WildDuck extends Duck {

    @Override
    public void quack() {

        System.out.println(" I am a real duck ");

    }

}
package com.ljq.factory;

/**
 * 
 * @author  Yilin 
 *
 */
public class RubberDuck extends Duck {

	@Override
	public void quack() {

		System.out.println(" I'm a rubber duck ,");

	}

}
package com.ljq.factory;

/**
 * 
 * @author  Yilin 
 *
 */
public class DonaldDuck extends Duck {

	@Override
	public void quack() {
		System.out.println(" I'm Donald Duck ");
	}

}

Then we need a waiter to communicate with the customer which one to buy ?:

package com.ljq.factory;

/**
 * 
 * @author  Yilin 
 *
 */
public class DuckFactory {

	private DuckFactory() {
	}

	private static DuckFactory duckFactory = new DuckFactory();

	public static final int WILD_DUCK = 1;

	public static final int RUBBER_DUCK = 2;

	public static final int DONALD_DUCK = 3;

	public static final int Pink_DUCK = 4;

	public static Duck getInstance(int duckType) {
		switch (duckType) {
		case WILD_DUCK:
			return new WildDuck();
		case RUBBER_DUCK:
			return new RubberDuck();
		case DONALD_DUCK:
			return new DonaldDuck();
		case Pink_DUCK:
			return new PinkDuck();
		default:
			return null;
		}
	}

}

Finally the guests came , The guests were very satisfied with our service , Bought all the varieties of our store at one go :

package com.ljq.factory;

/**
 * 
 * @author  Yilin 
 *
 */
public class Main {

	public static void main(String[] args) {
		Duck donaldDuck = DuckFactory.getInstance(DuckFactory.DONALD_DUCK);
		donaldDuck.quack();

		Duck wildDuck = DuckFactory.getInstance(DuckFactory.WILD_DUCK);
		wildDuck.quack();

		Duck pinkDuck = DuckFactory.getInstance(DuckFactory.Pink_DUCK);
		pinkDuck.quack();

		Duck rubberDuck = DuckFactory.getInstance(DuckFactory.RUBBER_DUCK);
		rubberDuck.quack();
	}

}

The results printed out by the console :

Above our simple factory model . Is it easier to understand in this way .

In the next issue, I will bring you Abstract factories and more knowledge , I hope my understanding will help you . See you next time !

原网站

版权声明
本文为[Yilin YL]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/175/202206241211506716.html