Understand singleton mode and factory mode (simple and easy to understand)

Singleton pattern

  • What is a singleton? There is only one instance during system operation.
  • Why have a singleton? Some objects in the system only need to be initialized once, such as players in KTV or initializing system parameters.
  • Requirements for singleton mode:
    1. A class with only one instance provides only a private constructor.
    private SingletonClass(){
          
            }  
    
    1. You must create this instance yourself to define a static private object of the class.
    private static SingletonClass single; 
    
    1. You must provide this instance to the system yourself. Create a public static method that returns this instance.
    public static SingletonClass getSingleton(){
          
          
        if(single==null){
          
          
            initSingleton();
        }
        return single;
    }
    

Hungry mode

I will create this instance for you whether you use it or not. (Official language: This instance is created when the class is loaded). Naturally thread-safe, the time it takes to obtain this object in each class is basically the same.

The following is the hungry pattern, using static inner classes to implement lazy loading.

public class SingleTon {
    
    
     
     private SingleTon() {
    
    
          
     }
     
     private static SingleTon singleTon;
    
        // 静态内部类
     public static class SingletonHelper{
    
    
          private static final SingleTon INSTANCE = new  SingleTon();
     }
     
     public static SingleTon getSingleTon() {
    
    
          singleTon = SingletonHelper.INSTANCE;
          return singleTon;
     }
     
}

lazy mode

This instance is only created when you call it. It is not thread-safe and it will take more time to obtain this object for the first time.

  • Thread safety issues
  • double check lock optimization
  • The compiler (JIT) and CPU may reorder instructions, resulting in the use of an uninitialized instance (nullpointException). This can be modified by adding the volatile keyword. For volatile-modified fields, instructions can be prevented from being reordered.
/**
 * 手写一个单例模式
 */
public class SingletonClass {
    
    

    // 1.私有化构造方法,收回创建实例的权限
    private SingletonClass(){
    
    

    }
    // 2.自己声明这个实例对象
    private volatile static SingletonClass singletonClass;

    // 3.向系统提供一个公共的方法,获取这个实例
    public static SingletonClass getInstance(){
    
    
        if(singletonClass==null){
    
     // 为空才加同步锁,锁的范围越小越好
            synchronized (SingletonClass.class){
    
    
                if(singletonClass==null){
    
     // 判断是否为空,防止实例化两次
                    singletonClass = new SingletonClass();
                    // 字节码 其中2和3可能存在重排的问题,如果3在前,在多线程的情况下会出现空指针
                    // 1.分配空间
                    // 2.初始化
                    // 3.引用赋值
                }
            }
        }
        return singletonClass;
    }

}

Compared

  1. Thread safety: Hungry style is inherently thread-safe, while lazy style itself is not thread-safe.
  2. Resource loading and performance: Hungry style instantiates a static object when the class is created. Regardless of whether this singleton will be used later, it will occupy a certain amount of memory, but accordingly, the speed will also be reduced when it is first called. Faster, because its resources have been initialized, and the lazy style, as the name suggests, will delay loading. The object will not be instantiated until the first time the singleton is used. Initialization must be done on the first call. If there is work to be done If there are more, there will be some delay in performance, and then it will be the same as Hungry Man style.

Factory pattern

  1. What is a factory? The object creation process is encapsulated in a factory class, and the object instance is obtained by calling the factory class method without directly using the new keyword to create the object.
  2. Why is there a factory pattern? The factory pattern can provide better code organization structure, better encapsulation, better scalability and better decoupling, thereby improving the quality and maintainability of the code.
  3. Factory pattern requirements
  • Abstract product: defines the common interface or abstract class of the product and describes the characteristics and behavior of the product.
  • Specific product: implements the abstract product interface or inherits the abstract product class, which is the target object created by the factory.
// 抽象产品接口
public interface Product {
    
    
    void operation1();
    void operation2();
}

// 具体类A
public class ConcreteProductA implements Product {
    
    
    @Override
    public void operation1() {
    
    
        // 具体类A的操作1
    }

    @Override
    public void operation2() {
    
    
        // 具体类A的操作2
    }
}

// 具体类B
public class ConcreteProductB implements Product {
    
    
    @Override
    public void operation1() {
    
    
        // 具体类B的操作1
    }

    @Override
    public void operation2() {
    
    
        // 具体类B的操作2
    }
}
  • Abstract factory: defines a common interface or abstract class of the factory and describes the method of creating products.
  • Concrete factory: A class that implements the abstract factory interface or inherits the abstract factory class and is responsible for actually creating products.
  • Client: Use the factory to create product code, and create the required product objects through the factory interface.
# 定义抽象工厂接口
class AbstractFactory:
    def create_product_a(self):
        pass

    def create_product_b(self):
        pass

# 实现具体的工厂类
class ConcreteFactory1(AbstractFactory):
    def create_product_a(self):
        return ProductA1()

    def create_product_b(self):
        return ProductB1()

class ConcreteFactory2(AbstractFactory):
    def create_product_a(self):
        return ProductA2()

    def create_product_b(self):
        return ProductB2()

# 定义产品接口
class AbstractProductA:
    def do_something(self):
        pass

class AbstractProductB:
    def do_something(self):
        pass

# 实现具体类
class ProductA1(AbstractProductA):
    def do_something(self):
        print("Product A1")

class ProductA2(AbstractProductA):
    def do_something(self):
        print("Product A2")

class ProductB1(AbstractProductB):
    def do_something(self):
        print("Product B1")

class ProductB2(AbstractProductB):
    def do_something(self):
        print("Product B2")

# 客户端代码
def client_code(factory):
    product_a = factory.create_product_a()
    product_b = factory.create_product_b()

    product_a.do_something()
    product_b.do_something()

# 使用具体工厂1
factory1 = ConcreteFactory1()
client_code(factory1)

# 使用具体工厂2
factory2 = ConcreteFactory2()
client_code(factory2)

Simple Factory Pattern

The simple factory pattern is also called the static factory pattern, which uses a factory class to create all product objects. The client only needs to create product objects through factory classes, without directly instantiating specific product classes. The core of the simple factory pattern is a factory class, which contains a method to create products, which determines which product to create based on the parameters passed in by the client.

# 定义产品接口
class Product:
    def show(self):
        pass

# 定义具体类A,实现接口
class ConcreteProductA(Product):
    def show(self):
        print("Concrete Product A")

# 定义具体类B,实现接口
class ConcreteProductB(Product):
    def show(self):
        print("Concrete Product B")

# 定义静态工厂类
class StaticFactory:
    @staticmethod
    def create_product(product_type):
        if product_type == "A":
            return ConcreteProductA()
        elif product_type == "B":
            return ConcreteProductB()
        else:
            raise ValueError("Invalid product type")

# 客户端代码
if __name__ == "__main__":
    product_a = StaticFactory.create_product("A")  # 使用静态工厂类创建具体A
    product_a.show()  # 调用具体A的方法,输出 "Concrete Product A"

    product_b = StaticFactory.create_product("B")  # 使用静态工厂类创建具体B
    product_b.show()  # 调用具体B的方法,输出 "Concrete Product B"

Factory Method Pattern

The factory method pattern delays the creation of specific products to subclasses, and each specific product corresponds to a specific factory class. The client creates product objects by calling factory methods, which are implemented by subclasses to create corresponding specific product objects.

// 抽象类
public abstract class Product {
    
    
    public abstract void use();
}

// 具体类A
public class ConcreteProductA extends Product {
    
    
    @Override
    public void use() {
    
    
        System.out.println("使用具体类A");
    }
}

// 具体类B
public class ConcreteProductB extends Product {
    
    
    @Override
    public void use() {
    
    
        System.out.println("使用具体类B");
    }
}

// 抽象工厂类
public abstract class Factory {
    
    
    public abstract Product createProduct();
}

// 工厂类A
public class ConcreteFactoryA extends Factory {
    
    
    @Override
    public Product createProduct() {
    
    
        return new ConcreteProductA();
    }
}

// 工厂类B
public class ConcreteFactoryB extends Factory {
    
    
    @Override
    public Product createProduct() {
    
    
        return new ConcreteProductB();
    }
}

// 客户端代码
public class Client {
    
    
    public static void main(String[] args) {
    
    
        Factory factoryA = new ConcreteFactoryA();
        Product productA = factoryA.createProduct();
        productA.use();
        
        Factory factoryB = new ConcreteFactoryB();
        Product productB = factoryB.createProduct();
        productB.use();
    }
}

Abstract Factory Pattern

The Abstract Factory pattern provides an interface for creating a series of related or interdependent objects without specifying their concrete classes. The abstract factory pattern contains an abstract factory interface that defines methods for creating product objects. The concrete factory class implements the abstract factory interface and is responsible for creating a series of related products. Each concrete factory class corresponds to a product family, and multiple products of this product family can be created.

// 定义抽象A
interface AbstractProductA {
    
    
    void operationA();
}

// 定义具体A1
class ConcreteProductA1 implements AbstractProductA {
    
    
    public void operationA() {
    
    
        System.out.println("Product A1");
    }
}

// 定义具体A2
class ConcreteProductA2 implements AbstractProductA {
    
    
    public void operationA() {
    
    
        System.out.println("Product A2");
    }
}

// 定义抽象B
interface AbstractProductB {
    
    
    void operationB();
}

// 定义具体B1
class ConcreteProductB1 implements AbstractProductB {
    
    
    public void operationB() {
    
    
        System.out.println("Product B1");
    }
}

// 定义具体B2
class ConcreteProductB2 implements AbstractProductB {
    
    
    public void operationB() {
    
    
        System.out.println("Product B2");
    }
}

// 定义抽象工厂
interface AbstractFactory {
    
    
    AbstractProductA createProductA();
    AbstractProductB createProductB();
}

// 定义具体工厂1
class ConcreteFactory1 implements AbstractFactory {
    
    
    public AbstractProductA createProductA() {
    
    
        return new ConcreteProductA1();
    }

    public AbstractProductB createProductB() {
    
    
        return new ConcreteProductB1();
    }
}

// 定义具体工厂2
class ConcreteFactory2 implements AbstractFactory {
    
    
    public AbstractProductA createProductA() {
    
    
        return new ConcreteProductA2();
    }

    public AbstractProductB createProductB() {
    
    
        return new ConcreteProductB2();
    }
}

// 调用方
public class Client {
    
    
    public static void main(String[] args) {
    
    
        // 创建工厂1
        AbstractFactory factory1 = new ConcreteFactory1();
        // 使用工厂1创建A和B
        AbstractProductA productA1 = factory1.createProductA();
        AbstractProductB productB1 = factory1.createProductB();
        productA1.operationA();
        productB1.operationB();

        // 创建工厂2
        AbstractFactory factory2 = new ConcreteFactory2();
        // 使用工厂2创建A和B
        AbstractProductA productA2 = factory2.createProductA();
        AbstractProductB productB2 = factory2.createProductB();
        productA2.operationA();
        productB2.operationB();
    }
}

Compared

  • The simple factory pattern is suitable for situations where the types of objects are small and do not change frequently. The factory method pattern is suitable for situations where there are many types of objects and new products may be added. The abstract factory pattern is suitable for creating a set of related or interdependent products. And there may be new product combinations added. Depending on specific needs and scenarios, choosing the appropriate factory pattern can improve the flexibility and maintainability of the code.
  • The simple factory pattern creates all product objects through a factory class and returns different specific product objects according to different parameters. In a multi-threaded environment, if multiple threads call the factory's creation method at the same time, thread safety issues may occur. One way to solve this problem is to lock the creation method of the factory class to ensure that only one thread can call this method at the same time.
  • The factory method pattern defers the creation of products to subclasses, and each product has a corresponding factory class to create. In a multi-threaded environment, each thread independently uses its own factory class to create product objects, and there is no thread safety issue. Different threads can call different factory classes concurrently to create products without interfering with each other.
  • The Abstract Factory pattern creates a family of related or dependent objects by providing an interface without specifying a specific class. In a multi-threaded environment, if multiple threads call different specific factory classes to create product objects at the same time, there is no thread safety issue. Different threads can concurrently call different specific factory classes to create products without interfering with each other.

Guess you like

Origin blog.csdn.net/m0_65491952/article/details/132452291