Singleton mode - factory mode

1: Singleton mode

1. Single instance mode can only have one instance

2. A singleton must create its own unique instance

3. A singleton must provide this instance to all other objects

In the computer system, the driver objects of thread pool, cache, log object, dialog box, printer and graphics card are often designed as singletons. These applications have the function of resource manager more or less.

Lazy singleton in singleton mode:

//0. Create your own singleton
class MySingle2{
    //6.2 create a static unique lock object
    static Object o = new Object();
    //1. Construction method of privatization class
    private MySingle2(){ }
    //2. The reference type variable of this type of object is created to save the address value of the object. The default value is null
    private static MySingle2 single2 ;
    //3. Provide public get methods
    synchronized public static MySingle2 getSingle2(){
        //4. Judge whether you have created an object before. If you have created an object before, go directly to return
        //If it has not been created before, go to if, create the object and return the object
        //6. There are shared data + multiple statements to operate data, so try to handle it in advance to avoid potential safety hazards of multi-threaded data
        //6.1 solution 1: add synchronization code block
        //6.2 solution 2: set this method getSingle2() as the synchronization method
        //Because all statements in this method need to be synchronized
        synchronized (o) {//Lock objects used in static methods also have to be static
            if (single2 == null) {//single2 is still the default value, indicating that no object has been created before
                single2 = new MySingle2();//It is created before it is created and assigned to single2
            }
            return single2;
        }
    }
}

Singleton mode:

//0. Create your own singleton
class MySingle{
    //1. Provide the construction method and privatize the construction method
    /*1.The purpose of privatization of construction method: to prevent the external world from creating this kind of object at will*/
    private MySingle(){ }

    //2. Create this type of object and privatize the object
    //4.2 since static resources can only call static resources, single objects also need to be set to static
    private static MySingle single = new MySingle();

    //3. Provide public access methods and return created objects
    //4.1 in order to call this method directly without passing through the object, this method needs to be set to static
    public static MySingle getSingle(){
        return single;
    }
}

2: Factory mode

Factory pattern is one of the most commonly used design patterns in Java. This is a design pattern of type. It is a creation pattern. It provides the best way to create objects. In factory mode, when creating objects, we do not expose the creation logic to the client, and point to the newly created objects by using a common interface. This pattern is used to encapsulate and manage the creation of objects

Through the factory mode, the right to create product instances is handed over to the factory. We no longer create objects through new. It reduces the direct coupling relationship between product users and users.

There are three variations of Factory mode:
(1) Simple factory mode: allows the interface to create objects, but does not expose the object creation logic.
(2) Factory method pattern: the interface is allowed to create objects, but the class used to create objects is determined by the subclass.
(3) Abstract factory pattern: abstract factory is an interface that can create a series of related objects without specifying / exposing their specific classes. This pattern can provide objects of other factories and create other objects inside them.
 

Simple factory mode:

Explain this mode using mobile production:

//Phone class: mobile phone Standard Specification class (AbstractProduct)

public interface Phone {
    void make(); 
}

//MiPhone class: manufacturing Xiaomi mobile phone (Product1)

public class MiPhone implements Phone {
    public MiPhone() {
        this.make();
    }
    @Override
    public void make() {
        // TODO Auto-generated method stub
        System.out.println("make xiaomi phone!");
    }
}

//IPhone s: manufacturing Apple phones (Product2)

public class IPhone implements Phone {
    public IPhone() {
        this.make();
    }
    @Override
    public void make() {
        // TODO Auto-generated method stub
        System.out.println("make iphone!");
    }
}

//PhoneFactory class: Mobile foundry (Factory)

public class PhoneFactory {
    public Phone makePhone(String phoneType) {
        if(phoneType.equalsIgnoreCase("MiPhone")){ //Judge whether the case of two strings is equal
            return new MiPhone();//If it exists, the corresponding object is returned
        }
        else if(phoneType.equalsIgnoreCase("iPhone")) {
            return new IPhone();
        }
        return null;
    }
}

//demonstration:

public class Demo {
   public static void main(String[] arg) {
       PhoneFactory factory = new PhoneFactory();//Create a factory object and call through the factory
       Phone miPhone = factory.makePhone("MiPhone");            // make xiaomi phone!
       IPhone iPhone = (IPhone)factory.makePhone("iPhone");    // make iphone!
   }
}



Factory method mode:

Compared with the simple factory mode in which the factory is responsible for producing all products, the factory method mode distributes the task of generating specific products to specific product factories, that is, it defines an abstract factory and defines the production interface of products, but instead of being responsible for specific products, it assigns the production tasks to different derived factories, This eliminates the need to create objects by specifying types.

The definitions of Phone class, MiPhone class and IPhone class related to the product remain unchanged:

//Phone class: mobile phone Standard Specification class (AbstractProduct)

public interface Phone {
    void make(); 
}

//MiPhone class: manufacturing Xiaomi mobile phone (Product1)

public class MiPhone implements Phone {
    public MiPhone() {
        this.make();
    }
    @Override
    public void make() {
        // TODO Auto-generated method stub
        System.out.println("make xiaomi phone!");
    }
}

//IPhone s: manufacturing Apple phones (Product2)

public class IPhone implements Phone {
    public IPhone() {
        this.make();
    }
    @Override
    public void make() {
        // TODO Auto-generated method stub
        System.out.println("make iphone!");
    }
}

//AbstractFactory class: an abstract class of factories that produce different products

public interface AbstractFactory { //It defines a factory that can produce different brands of mobile phones
    Phone makePhone();
}

//XiaoMiFactory class: a factory that produces Xiaomi mobile phones (ConcreteFactory1)

public class XiaoMiFactory implements AbstractFactory{
    @Override
    public Phone makePhone() {
        return new MiPhone();
    }
}

//AppleFactory class: the factory that produces Apple phones (ConcreteFactory2)

public class AppleFactory implements AbstractFactory {
    @Override
    public Phone makePhone() {  
        return new IPhone();
    }
}

//demonstration:

public class Demo {
    public static void main(String[] arg) {
        AbstractFactory miFactory = new XiaoMiFactory();
        AbstractFactory appleFactory = new AppleFactory();
        miFactory.makePhone();            // make xiaomi phone!
        appleFactory.makePhone();        // make iphone!
    }
}

Summary:

The difference between simple factory and factory method mode is that the behavior of the former to generate products is encapsulated in a method, instantiated according to the type of parameters, and there is no abstract interface. The latter adds an abstract factory to create different products by implementing different factory methods. A method usually corresponds to a product. This method is more scalable than the former. When the demand increases, it fully conforms to the principles of opening and closing and dependency inversion

Abstract factory pattern:

No matter how the factory splits and abstracts the above two modes, they are only for one kind of product Phone (abstract product). How should they be expressed if another product PC is to be produced?

The simplest way is to completely copy the factory method mode introduced in 2, but this time it is a PC. But at the same time, it means that we should completely copy and modify all the code of Phone production management. Obviously, this is a stupid method and is not conducive to expansion and maintenance.

Abstract factory mode adds an interface for creating products in AbstarctFactory, and realizes the creation of new products in specific sub factories. Of course, the premise is that the sub factories support the production of the products. Otherwise, the inherited interface can do nothing
 

Still demonstrate through mobile phone cases:

//1.Phone: mobile phone Standard Specification (AbstractProduct)-----

public interface Phone {
    void make(); 
}

//MiPhone class: manufacturing Xiaomi mobile phone (Product1)

public class MiPhone implements Phone {
    public MiPhone() {
        this.make();
    }
    @Override
    public void make() {
        // TODO Auto-generated method stub
        System.out.println("make xiaomi phone!");
    }
}

//IPhone s: manufacturing Apple phones (Product2)

public class IPhone implements Phone {
    public IPhone() {
        this.make();
    }
    @Override
    public void make() {
        // TODO Auto-generated method stub
        System.out.println("make iphone!");
    }
}

//2.PC class: defines the interface of PC products (AbstractPC)-----

public interface PC {
    void make();
}

//MiPC class: define Xiaomi computer products (MIPC)

public class MiPC implements PC {
    public MiPC() {
        this.make();
    }
    @Override
    public void make() {
        // TODO Auto-generated method stub
        System.out.println("make xiaomi PC!");
    }
}

//Mac class: defines Apple computer products (MAC)

public class MAC implements PC {  //All realize PC
    public MAC() {
        this.make();    
    }
    @Override
    public void make() {
        // TODO Auto-generated method stub
        System.out.println("make MAC!");
    }
}

//Next, modify the definitions of factory related classes:
//3.AbstractFactory class: add PC product manufacturing interface------

public interface AbstractFactory {
    Phone makePhone();
    PC makePC();
}

//XiaoMiFactory class: increase the manufacturing of Xiaomi PC (ConcreteFactory1)

public class XiaoMiFactory implements AbstractFactory{
    @Override
    public Phone makePhone() {
        return new MiPhone();
    }
    @Override
    public PC makePC() {
        return new MiPC();
    }
}


//AppleFactory class: add Apple PC manufacturing (ConcreteFactory2)

public class AppleFactory implements AbstractFactory {
    @Override
    public Phone makePhone() {//Define multiple products through the interface to enable the business to realize new products
        return new IPhone();
    }
    @Override
    public PC makePC() {
        return new MAC();
    }
}

//Demo 4.:
public class Demo {
    public static void main(String[] arg) {
        AbstractFactory miFactory = new XiaoMiFactory();
        AbstractFactory appleFactory = new AppleFactory();
        miFactory.makePhone();            // make xiaomi phone!
        miFactory.makePC();                // make xiaomi PC!
        appleFactory.makePhone();        // make iphone!
        appleFactory.makePC();            // make MAC!
    }
}

Summary:

Abstract factory pattern is an upgraded version of factory method pattern. The latter is for a single product, while the former is for a product family. According to the official definition: provide an interface for creating a set of related / interdependent objects without specifying their specific classes.
For example, an automobile factory needs to generate bicycles, and each car has a series of products such as doors and tires, which means that for each additional car, a new factory needs to be added to provide the realization of new products. At this time, the abstract factory pattern can be used for design. The abstract factory pattern is applicable to a series of product families.

Keywords: Java Singleton pattern

Added by jamesl on Wed, 29 Dec 2021 21:15:05 +0200