preface

This article aims to quickly comb through common design patterns and understand what situations each pattern mainly targets at and its basic characteristics. Each pattern is preceded by one or more reference pages that can be read in depth for readers to understand its implementation in detail.

Divided into three articles:

  • Part I: Design Patterns basic concepts and creative design patterns
  • Part II: Behavioral design patterns
  • Part TWO: Structural design pattern

Quick memory

Create a type

  • Singleton
  • The factory pattern
    • Simple Factory
    • Factory Method
    • Abstract Factory
  • Generator (Builder)
  • Prototype mode

concept

First of all, design patterns are not artful techniques. They are not bizarre techniques. A design pattern is simply a design idea that designs code structures in different ways for different business scenarios, with the ultimate goal of decoupling and, by extension, scalability and robustness, but on top of decoupling.

High cohesion and low coupling

High cohesion: in the system, modules A and B interact with each other. If the modification of module A does not affect the work of module B, then A is considered to be sufficiently cohesive.

Low coupling: that is, module A and module B are dependent on each other, so when B changes, module A can still work normally, so A and B are considered to be low coupling.

Create a type

The singleton pattern

Please refer to Github for a full explanation, and the points below are just for a quick review. Github writes well.

Also refer to:

blog.jobbole.com/109449/

intentions

Ensure that there is only one instance of a class and provide a global access point for that instance.

The class diagram

Use a private constructor, a private static variable, and a public static function.

Private constructors ensure that object instances cannot be created using constructors, only public static functions that return unique private static variables.

implementation

Lazy (lazy instantiation) — thread safety/double check

Privatize constructor

Declare a static singleton

3. Before constructing a singleton, add a lock (a static object) or synchronized to a method.

You need to check whether a singleton instance has been constructed twice, before and after the lock

Using the lock (obj)

Public class Singleton {private Singleton() {} public class Singleton {private static Singleton() {} Private static object obj= new object(); private static object obj= new object(); Public static Singleton GetInstance() public static Singleton GetInstance() {if (single == null) If (single == null) {single = new Singleton(); } } } return single; }}Copy the code

Using a synchronized (Singleton. Class)

public class Singleton { private Singleton() {} private volatile static Singleton uniqueInstance; public static Singleton getUniqueInstance() { if (uniqueInstance == null) { synchronized (Singleton.class) { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } } } return uniqueInstance; }}Copy the code
May ask questions

0. Why test twice?

If two threads execute an IF statement at the same time, both threads enter the if statement block at the same time. Both threads execute uniqueInstance = new Singleton(), even though the lock is inside the if block; This statement is only a matter of order, that is, it will be instantiated twice, resulting in two instances. Therefore, a double check lock must be used, that is, two if statements are required.

1. Can constructors be public?

No, the constructor of a singleton class must be privatized. Singleton classes cannot be instantiated. Singleton instances can only be called statically.

2. Why is the object locked to an int?

No, the lock must be a reference type. If a lock value type is declared with a different address for each thread, then the last thread’s lock will be considered unlocked by the next thread.

3. Use volatile to modify uniqueInstance

uniqueInstance = new Singleton(); This code is actually executed in three steps.

Allocate memory Space The initialization object points uniqueInstance to the allocated memory addressCopy the code

However, due to the reordering nature of the JVM, it is possible that the order of execution changes to 1>3>2

public class Singleton { private volatile static Singleton uniqueInstance; Private Singleton(){} public static Singleton getInstance(){if(uniqueInstance == null){// B thread detects that uniqueInstance is not null synchronized(Singleton.class){ if(uniqueInstance == null){ uniqueInstance = new Singleton(); // thread A was ordered to be rearranged. But I haven't finished executing the constructor yet. } } } return uniqueInstance; // Subsequent B thread execution will raise: object not initialized error. }}Copy the code

Hungry – Thread safe

The thread unsafe problem is mainly due to uniqueInstance being instantiated more than once. If uniqueInstance is directly instantiated, it will not be instantiated more than once and thus will not cause thread unsafe problems. But the direct instantiation approach also loses the resource savings of delayed instantiation.

private static Singleton uniqueInstance = new Singleton();
Copy the code

Static inner class implementation

When the Singleton class is loaded, the static inner class SingletonHolder is not loaded into memory. SingletonHolder is loaded only when the getUniqueInstance() method is invoked to trigger SingletonHolder.instance, at which point the INSTANCE INSTANCE is initialized.

This approach not only has the benefit of delayed initialization, but also provides thread-safe support by the virtual machine.

public class Singleton {

    private Singleton(a) {}

    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getUniqueInstance(a) {
        returnSingletonHolder.INSTANCE; }}Copy the code

Enumeration implementation

This is a best practice for the singleton pattern, which is simple to implement and prevents multiple instantiations in the face of complex serialization or reflection attacks.

public enum Singleton {
    uniqueInstance;
}
Copy the code

Consider the following implementation of the Singleton, which creates a new instance each time it serializes. To ensure that only one instance is created, you must declare all fields transient and provide a readResolve() method.

public class Singleton implements Serializable {

    private static Singleton uniqueInstance;

    private Singleton(a) {}public static synchronized Singleton getUniqueInstance(a) {
        if (uniqueInstance == null) {
            uniqueInstance = new Singleton();
        }
        returnuniqueInstance; }}Copy the code

If you do not use enumerations to implement the singleton pattern, reflection attacks occur because the setAccessible() method allows you to set the access level of a private constructor to public and then call the constructor to instantiate the object. If you want to prevent this attack, you need to add code in the constructor to prevent instantiation of the second object.

As you can see from the discussion above, solving serialization and reflection attacks is a hassle that enumeration implementations don’t have, so it’s a best practice to implement the singleton pattern with enumeration.

Usage scenarios

  • Logger Classes
  • Configuration Classes
  • Accesing resources in shared mode
  • Factories implemented as Singletons

Simple/Static Factory

www.jianshu.com/p/d1b6731c1…

define

Create an object without exposing the internal details to the customer, and provide a common interface for creating objects.

In the simple factory pattern, you can return instances of different classes depending on the parameters.

The simple factory pattern specifically defines a class that is responsible for creating instances of other classes

structure

The simple Factory pattern contains the following roles:

  • Factory: Factory role

The factory role is responsible for implementing the internal logic that creates all instances

  • Product: Abstract Product role

Abstract product roles are the parent classes of all objects created and are responsible for describing the common interfaces shared by all instances

  • ConcreteProduct: ConcreteProduct roles

A concrete product role is a creation target, and all created objects act as instances of a concrete class of that role.

implementation

public class Test { public static void main(String[] args) { String loginType = "password"; String name = "name"; String password = "password"; Login login = LoginManager.factory(loginType); boolean bool = login.verify(name, password); If (bool) {/ * * * * business logic /} else {/ * * * * business logic /}}}Copy the code

The advantages and disadvantages

advantages

Easy to construct and simple logic.

disadvantages

If there is a new product to be added, we need to add a new product class at the same time, and we need to modify the factory class and add an else if branch. This violates the open – close rule of closing changes.

2. The instance creation logic of all classes is collected in one factory class, which violates the principle of responsibility assignment of high cohesion. All creation logic is concentrated in one factory class, and all business logic is realized in this factory class. When it doesn’t work, the whole system is affected. Therefore, it should be used only in very simple cases, such as when the factory class is responsible for creating a small number of objects.

3. The simple factory pattern uses a static factory approach that prevents the factory roles from forming an inheritance-based hierarchy.

Apply to the environment

The factory class is responsible for creating fewer objects: Because there are fewer objects created, the business logic in the factory method is not too complicated.

JDK

The simple factory pattern is widely used in JDK libraries, such as the java.text.dateFormat utility class, which is used to format a local date or time.

public final static DateFormat getDateInstance();
public final static DateFormat getDateInstance(int style);
public final static DateFormat getDateInstance(int style,Locale
locale);
Copy the code

②Java encryption technology to obtain different encryption algorithm key generator:

KeyGenerator keyGen=KeyGenerator.getInstance("DESede");
Copy the code

Create password:

Cipher cp = Cipher.getInstance("DESede");
Copy the code

Factory Method

www.jianshu.com/p/1cf9859e0…

intentions

Also called the Polymorphic Factory pattern/Virtual Constructor pattern/Polymorphic Factory pattern

That is, factory subclasses are used to determine which specific product classes should be instantiated.

Use motivation

Instead of designing a single button factory class to be responsible for all product creation, you delegate the creation of specific buttons to a specialized factory subclass.

We define an abstract button factory class and then a concrete factory class to generate circular buttons, rectangular buttons, diamond buttons, and so on, which implement the methods defined in the abstract button factory class. To this structure as a result of this abstract concrete under the condition of the factory class can be changed without introducing new products, if there is a new type button, only need for this new type of button to create a specific factory class can get the new button on the instance, this feature will make the factory method pattern has surmounted the advantages of simple factory pattern, More in line with the “open and closed principle”.

role

  • Product: Abstract Product, a superclass of objects created by the factory method pattern, that is, a common parent or shared interface for all Product classes. In real systems, this role is also often implemented using abstract classes.

  • ConcreteProduct: a ConcreteProduct. This role implements the interface declared by the abstract Product. Each object created by the factory method pattern is an instance of a ConcreteProduct.

  • Factory: Abstract Factory. In this role is the core of the Factory method pattern. Any Factory class that creates objects in the pattern must implement this interface. In real systems, this role is also often implemented using abstract classes.

  • ConcreteFactory: ConcreteFactory: a concrete Java class that implements an abstract factory interface. Concrete factory roles contain business-specific logic and are invoked by consumers to create concrete product objects.

implementation

See the link for details

Client call

Static void Main(string[] args) {ICreator creator = new BulbCreator(); ILight light = creator.CreateLight(); light.TurnOn(); light.TurnOff(); Creator = new TubeCreator(); light = creator.CreateLight(); light.TurnOn(); light.TurnOff(); }Copy the code

The advantages and disadvantages

advantages

① In the factory method pattern, the factory method is used to create the product that the customer needs, and it also hides the details of which specific product class will be instantiated from the customer. The user only needs to care about the factory corresponding to the product, and does not need to care about the creation details, or even need to know the class name of the specific product class.

② The factory method pattern is also called polymorphic factory pattern because all concrete factory classes have the same abstract parent class.

③ Another advantage of using the factory method pattern is that when adding a new product into the system, there is no need to modify the abstract factory and the interface provided by the abstract product, no need to modify the client, and no need to modify other concrete factory and concrete product, but only a concrete factory and concrete product can be added. As a result, the system is very scalable, fully adhering to the “open closed principle”, which is better than the simple factory model.

disadvantages

(1) When adding new products, it is necessary to write new specific product classes, but also to provide the corresponding specific factory classes, the number of classes in the system will increase in pairs, increasing the complexity of the system to a certain extent, there are more classes to compile and run, will bring some extra overhead to the system.

(2) Considering the scalability of the system, it is necessary to introduce an abstraction layer, which is defined in the client code, increasing the abstraction and difficulty of understanding of the system, and DOM, reflection and other technologies may be used in the implementation, increasing the difficulty of the implementation of the system.

JDK

  • Factory methods in JDBC:
Connection conn=DriverManager.getConnection("jdbc:microsoft:sqlserver://localhost:1433; DatabaseName=DB; user=sa; password="); Statement statement=conn.createStatement(); ResultSet rs=statement.executeQuery("select * from UserInfo");Copy the code
  • java.util.Calendar
  • java.util.ResourceBundle
  • java.text.NumberFormat
  • java.nio.charset.Charset
  • java.net.URLStreamHandlerFactory
  • java.util.EnumSet
  • javax.xml.bind.JAXBContext

Abstract Factory

www.jianshu.com/p/d6622f3e7…

define

Product hierarchy: hierarchy the inheritance structure of products, such as an abstract class is a TV set, its subclasses are haier, hisense TV, TCL, TVS, abstract and specific brands, constitute a product hierarchy between abstraction is the parent of the television, and specific brand of TV set is its subclasses.

Product family: in the abstract factory pattern, product family is to point to by the same factory, located in different level of product structure in a set of products, such as haier electrical appliances factory production of TV sets, refrigerators, haier haier haier TV in the TV product hierarchy, haier refrigerators in the refrigerator in the hierarchy.

Abstract factory pattern is the most abstract and general form of all factory patterns.

The biggest difference between the abstract factory pattern and the factory method pattern is the abstract factory pattern

The factory method pattern addresses one product hierarchy, while the abstract factory pattern addresses multiple product hierarchies. One factory hierarchy can be responsible for creating product objects in multiple different product hierarchies.

role

The abstract factory pattern contains the following roles:

  • AbstractFactory: AbstractFactory
  • ConcreteFactory: ConcreteFactory
  • AbstractProduct: AbstractProduct
  • Product: Specific Product

implementation

Abstract product: Apple series

public interface Apple
     {
        void AppleStyle();
    }
Copy the code

Specific product: iPhone

public class iphone implements Apple
     {
         public void AppleStyle()
         {
            Console.WriteLine("Apple's style: iPhone!");
        }
     }
Copy the code

The abstract factory

public interface Factory
     {
         Apple createAppleProduct();
         Sumsung createSumsungProduct();
     }
Copy the code

Mobile phone factory

public class Factory_Phone implements Factory { public Apple createAppleProduct() { return new iphone(); } public Sumsung createSumsungProduct() { return new note2(); }}Copy the code

call

public static void Main(string[] args)
         {
             // The buyer wants an iPad and a Tab
              Factory factory = new Factory_Pad();
              Apple apple = factory.createAppleProduct();
              apple.AppleStyle();
              Sumsung sumsung = factory.createSumsungProduct();
              sumsung.BangziStyle();
  
             // The buyer wants another iPhone and a Note2
            factory = new Factory_Phone();
             apple = factory.createAppleProduct();
             apple.AppleStyle();
             sumsung = factory.createSumsungProduct();
             sumsung.BangziStyle();
         }
Copy the code

The advantages and disadvantages

advantages

(1) Abstract factory pattern can achieve high cohesion and low coupling design purpose, so abstract factory pattern has been widely used.

② It is very convenient to add new specific factories and product families, because a specific factory implementation represents a product family, there is no need to modify the existing system, in line with the “open and closed principle”.

disadvantages

Inclination of the open close principle (easy to add new factories and product families, troublesome to add new product grade structure)

Apply to the environment

The abstract factory pattern can be used when:

① It is important for all types of factory patterns that a system should not depend on the details of how product class instances are created, composed, and expressed.

② There is more than one product family in the system, and only one product family is used at a time. (Difference from factory method pattern)

③ Products belonging to the same product family will be used together, and this constraint must be reflected in the design of the system.

④ The system provides a library of product classes, all products appear in the same interface, so that the client does not depend on the concrete implementation.

JDK

  • javax.xml.parsers.DocumentBuilderFactory
  • javax.xml.transform.TransformerFactory
  • javax.xml.xpath.XPathFactory

Generator (Builder)

Blog.csdn.net/c275046758/…

intentions

Encapsulates the construction of an object and allows step-by-step construction.

implementation

See the reference link for the implementation code

The one-cup factory produces all kinds of cups, no matter what shape they are, but they all include strings, hats and cups. Create various types of cups from this model.

JDK

  • java.lang.StringBuilder
  • java.nio.ByteBuffer
  • java.lang.StringBuffer
  • java.lang.Appendable
  • Apache Camel builders

Prototype mode

www.cnblogs.com/lwbqqyumidi…

intentions

From an existing object, more new objects with the same type as this object are copied.

Shallow clone() :

We know that the definition of a class includes attributes and methods. Properties are used to represent the state of the object, and methods are used to represent the behavior that the object has. Properties can be either Java primitive data types or reference types.

Shallow replication in Java is usually done using clone().

When shallow replication is performed, the Clone function returns a reference to the new Clone object, which occupies a different heap space from the original object. At the same time, the copied object has the same state as the original object.

Here, the consistent state of the object means that the copied object is exactly the same as the property value of the original object ==.

Deepclone () :

Deep copy in Java is typically achieved through object serialization and deserialization. When serializing, you need to implement the Serializable interface.

As you can see from the output, deep replication not only creates space in the heap memory to store the copied objects, but also copies the objects referred to by the attributes of the reference types in the objects, reopening the heap space storage.

JDK

  • java.lang.Object#clone()
  • deepclone()

—– End —–

For more exciting articles, please check out my blog or follow me on my official account: Rude3Knife

Full review manual article navigation

Click below: Technical Tweets — Interview Sprint

Full Review Manual Article Navigation (CSDN)

Knowledge points review manual article recommendation

  • Java Basics Interview Manual
  • Java container (List, Set, Map) quick review manual
  • Java Concurrent Knowledge quick review manual (part 1)
  • Java Concurrent Knowledge quick review manual (ii)
  • Java Virtual Machine Knowledge quick review manual (part 1)
  • Java Virtual Machine Quick Review manual (part 2)
  • Quick review of 23 commonly used design patterns
  • Redis Basic Knowledge interview manual
  • Leetcode (top 150 questions)
  • Summary of small algorithms often asked in interviews
  • Search algorithm summary and some algorithms implemented in Python/Java
  • Sorting algorithm implementation and summary Python/Java
  • HTTP should know should know knowledge review manual (1)
  • HTTP should know should know knowledge review manual (ii)
  • . Etc. (please see the full review manual navigation)

Pay attention to my

Personal Blog:

  • CSDN: @ Rude3Knife
  • Zhihu: @ Zhendong
  • Jane: @pretty three knives a knife
  • Nuggets: @ pretty three knife knife
  • Public account: Back-end technology ramble