Preface:

Invited by a child, we will continue to share design patterns. The basic introduction of design patterns has been described in the last article, so we will not repeat it in this article. Today I will introduce you to the inside of the introduction to design patterns – singleton patterns. Learning these patterns helps inexperienced developers learn software design in an easy and quick way.

Akik Conscience still lives

Welcome to follow the wechat public account: Yu Linjun

Or add the author’s wechat account: Become_me


Singleton schema concept definition

The singleton pattern is one of the simplest design patterns we use, and this type of design pattern belongs to the creator type pattern. Specifies that a class has only one instance and that the class can create its own instance.

For example, in some application programming, we will define some unique driver classes, which will only have one instance. By using the singleton pattern, we can avoid unnecessary multiple instances of the class to reduce memory waste, or cause data inconsistencies.

Structure definition:

Singleton class: a class that contains an instance and can create its own instance.

Access classes: Classes that use singletons.

The structure diagram is as follows

The singleton pattern is one of the simplest design patterns. In general, the constructors of ordinary classes are public, and external classes can generate multiple instances through the “new constructor ()”. However, if you make the constructor of a class private, the external class cannot call that constructor and therefore cannot generate multiple instances. The class itself must define a static private instance and provide a static public function to create or get the static private instance.

Here are some examples of code used in common singleton patterns:

Type 1: lazy singleton

This pattern is characterized by the fact that no singleton is generated when the class is loaded, and the singleton is created only when the getlnstance method is first called.

Here’s an example:
C + + implementation
#include <iostream> using namespace std; class Signleton { private: Signleton() { cout << "init singleton" << endl; } static Signleton* _instance; public: static Signleton* getInstance() { if(_instance == nullptr) { _instance = new Signleton; } return _instance; }}; Signleton * Signleton:: _instance = nullptr; int main() { // Signleton obj1; Signleton::getInstance(); Signleton::getInstance(); Signleton::getInstance(); return 0; }Copy the code
Python implementation
#! /usr/bin/python3 class Singleton(object): def __init__(self): print("init singleton") @classmethod def instance(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): Singleton._instance = Singleton(*args, **kwargs) return Singleton._instance if __name__ == "__main__": obj1 = Singleton.instance() obj2 = Singleton.instance() obj3 = Singleton.instance()Copy the code

Type 2: Hangry singleton

This pattern is characterized by creating a singleton as soon as the class is loaded, ensuring that the singleton exists before the getInstance method is called.

Here’s an example:
C + + implementation
#include <iostream> using namespace std; class Signleton { private: Signleton() { cout << "init singleton" << endl; } static Signleton _instance; public: static Signleton getInstance() { return _instance; }}; Signleton Signleton:: _instance ; int main() { Signleton::getInstance(); Signleton::getInstance(); Signleton::getInstance(); return 0; }Copy the code
Python implementation
#! /usr/bin/python3 class Singleton(object): _instance = None def __init__(self): if not Singleton._instance: print("init singleton") @classmethod def instance(cls): if not cls._instance: cls._instance = Singleton() return cls._instance if __name__ == "__main__": obj1 = Singleton.instance() obj2 = Singleton.instance() obj3 = Singleton.instance() print(Singleton.instance()) print(Singleton.instance()) print(Singleton.instance())Copy the code

After compiling, you can see that we called it three times, but the constructor was actually executed only once.

Comparison of two ways to create a singleton:

Lazy: This class is created only when it is called. If multiple threads are used at the same time, thread-safety considerations are considered. This code is only suitable for a single thread, when multithreading, is not safe, multithreading locks. Considering that both threads call instance for the first time simultaneously and both detect that P is nullptr, both threads construct an instance of P simultaneously, which would violate the singleton rule.

Hungry: When a class is loaded, the class is instantiated. It is not used but consumes memory, so it is thread safe because it is instantiated from the start.

Type 3: Optimized version (the version I use a lot)

Here’s an example:
C + + implementation
#include <iostream> using namespace std; class Signleton { private: Signleton() { cout << "init singleton" << endl; } public: static Signleton getInstance() { static Signleton m_instance; return m_instance; }}; Signleton Signleton:: _instance ; int main() { Signleton::getInstance(); Signleton::getInstance(); Signleton::getInstance(); return 0; }Copy the code

This is often used in work, using a local static variable, the code is relatively simple, preferred to use this.

Added: initialization of static objects in C++

Non-local Static objects (outside of functions)

C++ states that the initialization of a non-local static object takes place before the execution of main, i.e. during the single-thread startup phase before main, so there is no thread-safety issue. However, C++ does not specify the initialization order of multiple non-local static objects, especially non-local static objects from multiple compilation units. Their initialization order is random.

Local static object (inside function)

For a Local static object, initialization occurs when the control flow first executes an initialization statement for the object. Control flows from multiple threads may reach their initialization statements at the same time.

Prior to C++11, initialization of local static objects in multithreaded environments was not thread-safe. If a thread is executing a local static object initialization statement but has not completed the initialization, and other threads are executing the statement, the thread will assume that it is executing the statement for the first time and enter the constructor of the local static object. This can lead to repeated construction of the local static object, which can lead to memory leaks. Therefore, the repeated construction of local static objects in a multi-threaded environment needs to be solved.

C++11 addresses this problem in the language specification. C++11 states that from the time a thread starts to initialize a local static object to the time it completes the initialization, other threads will wait until the local static object is initialized.

Advantages and disadvantages of the singleton pattern

Advantages of the singleton pattern:

The singleton ensures that there is only one instance in memory, reducing the memory overhead.

Multiple occupancy of resources can be avoided.

The singleton mode sets global access points that optimize and share access to resources.

Disadvantages of the singleton pattern:

The singleton mode generally has no interface and is difficult to expand. If you want to extend, there is no other way than to modify the original code, violating the open closed principle.

In concurrent testing, the singleton pattern is not conducive to code debugging. During debugging, you cannot simulate generating a new object if the code in the singleton is not executed.

The singleton function code is usually written in a class, and it is easy to violate the single responsibility principle if the function is not properly designed.

conclusion

This is the singleton pattern in the design pattern I share. If you have better ideas and requirements, you are welcome to add my friend to share.


Author: conscience still, hard work during the day, at night original public number Lord. In addition to the content of the public number, there are also some feelings of life, a serious output content of the workplace old driver, but also a technology to enrich life, photography, music and basketball. Watch me, walk with me.

· · · · · · · · · · · · · · · · END · · · · · · · · · · · · · · · ·Copy the code

Recommended reading

[1] C++ smart pointer do you know?

[2] A brief introduction of software framework for embedded low-level development

[3] How does a program in the CPU run as a must-read

[4] Cartographer environment building and drawing building test

[5] Comparison of simple factory model, factory model and abstract factory model

This public account all original dry goods have been sorted into a catalogue, reply [resources] can be obtained.