preface

Design Pattern is a set of repeatedly used, most people know, classified, summarized code Design experience, the use of Design Pattern in order to reuse the code, make the code easier to understand and ensure the reliability of the code.

This paper mainly introduces the simple factory model and its typical application, as follows:

  • Introduction to the simple factory pattern
  • Simple factory model typical application and source code analysis
    • Calendar class gets the Calendar class object
    • JDBC gets the database connection
    • LoggerFactory gets the Logger object

Simple Factory model

Factory pattern is one of the most commonly used creation design patterns, including abstract factory pattern, factory method pattern and simple factory pattern, simple factory pattern is the simplest one

Simple Factory Pattern: Defines a Factory class that can return instances of different classes depending on the parameters. The created instances usually have a common parent class.

Because the methods used to create instances in the simple Factory pattern are static methods, the simple Factory pattern is also known as the static Factory Method pattern. It belongs to the class-creation pattern, but not to the GOF23 design pattern

role

Factory (Factory Role) : The Factory role is the Factory class, which is the core of the simple Factory pattern and is responsible for implementing the internal logic that creates all product instances; The factory class can be called directly from the outside world to create the desired product object. The factory class provides a static factoryMethod, factoryMethod(), whose return type is abstract Product type

Product (Abstract Product role) : It is the parent of all objects created by the factory class and encapsulates the common methods of various Product objects. Its introduction will increase the flexibility of the system so that only one generic factory method needs to be defined in the factory class, since all concrete Product objects created are subclass objects.

ConcreteProduct: This is the creation target of the simple factory pattern, and all created objects act as instances of a concrete class for this role. Each concrete product role inherits the abstract product role and needs to implement the abstract methods declared in the abstract product

The simple Factory pattern, in which the client creates an instance of a product class through the factory class rather than directly using the new keyword to create objects, is the simplest member of the factory pattern family

The sample

Abstract product class Video defines abstract method produce()

public abstract class Video {
    public abstract void produce();
}
Copy the code

The concrete product classes JavaVideo and PythonVideo both inherit from the abstract product class Video

public class JavaVideo extends Video {
    @Override
    public void produce() {
        System.out.println("Recording a Java course video");
    }
}

public class PythonVideo extends Video {
    @Override
    public void produce() {
        System.out.println("Recording a Python course video"); }}Copy the code

The factory class implements two methods: using if-else judgment and using reflection to create objects

Public class VideoFactory {/** * useif elseJudge the type,typeFor Java, return JavaVideo,typePythonVideo */ public Video getVideo(String)type) {
        if ("java".equalsIgnoreCase(type)) {
            return new JavaVideo();
        } else if ("python".equalsIgnoreCase(type)) {
            return new PythonVideo();
        }
        returnnull; } /** * public Video getVideo(Class c) {Video Video = null; try { video = (Video) Class.forName(c.getName()).newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); }returnvideo; }}Copy the code

Use a client to invoke the factory class

public class Test {
    public static void main(String[] args) {
        VideoFactory videoFactory = new VideoFactory();
        Video video1 = videoFactory.getVideo("python");
        if (video1 == null) {
            return;
        }
        video1.produce();

        Video video2 = videoFactory.getVideo(JavaVideo.class);
        if (video2 == null) {
            return; } video2.produce(); }}Copy the code

The output

Recording a Python course Video Recording a Java course videoCopy the code

The Test class gets the object by passing an argument to VideoFactory.getVideo(). The logic of creating the object is left to the VideoFactory class

Summary of the simple factory pattern

The main advantages of the simple factory pattern are as follows:

  • The factory class contains the necessary judgment logic to decide when to create which instance of a product class, the client can be relieved of the responsibility of directly creating the product object and simply “consuming” the product, and the simple factory pattern enables the separation of object creation and usage.
  • The client does not need to know the class name of the specific product class created, but only needs to know the corresponding parameters of the specific product class. For some complex class names, simple factory mode can reduce the user’s memory to a certain extent.
  • By introducing configuration files, new specific product classes can be replaced and added without modifying any client code, increasing the flexibility of the system to some extent.

The main disadvantages of the simple factory pattern are as follows:

  • Because the factory class centralizes the creation logic for all products, it is so overloaded that if it does not work properly, the entire system will suffer.
  • Using the simple factory pattern inevitably increases the number of classes in the system (introducing new factory classes), increasing the complexity and difficulty of understanding the system.
  • It is difficult to expand the system. Once new products are added, the factory logic has to be modified. When there are too many product types, the factory logic may be too complex, which is not conducive to the expansion and maintenance of the system and violates the open and close principle.
  • The simple factory pattern uses a static factory approach that prevents the factory roles from forming an inheritance-based hierarchy.

Applicable scenarios:

  • The factory class is responsible for creating fewer objects, so the business logic in the factory method is not too complicated because there are fewer objects to create.
  • The client only knows the parameters passed into the factory class and does not care how the object is created.

Simple factory model typical application and source code analysis

Calendar class gets the Calendar class object

Calendar abstract class, the subclasses of this class are BuddhistCalendar, JapaneseImperialCalendar, GregorianCalendar, RollingCalendar and so on

The getInstance method, which gets a Calendar subclass object based on the parameters, actually passes the parameters to the createCalendar method, CreateCalendar creates a subclass object using provider or Switch or if-else based on the parameters

The following is the code for the Calendar class in Java8, which is implemented as if-else in Java7

public static Calendar getInstance(TimeZone zone, Locale aLocale) {
    return createCalendar(zone, aLocale);
}

private static Calendar createCalendar(TimeZone zone, Locale aLocale) {
    CalendarProvider provider = LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale).getCalendarProvider();
    if(provider ! = null) { try {return provider.getInstance(zone, aLocale);
        } catch (IllegalArgumentException iae) {
        }
    }

    Calendar cal = null;

    if (aLocale.hasExtensions()) {
        String caltype = aLocale.getUnicodeLocaleType("ca");
        if(caltype ! = null) { switch (caltype) {case "buddhist":
	            	cal = new BuddhistCalendar(zone, aLocale); break;
	            case "japanese":
	                cal = new JapaneseImperialCalendar(zone, aLocale); break;
	            case "gregory":
	                cal = new GregorianCalendar(zone, aLocale); break; }}}if (cal == null) {
        if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
            cal = new BuddhistCalendar(zone, aLocale);
        } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja" && aLocale.getCountry() == "JP") {
            cal = new JapaneseImperialCalendar(zone, aLocale);
        } else{ cal = new GregorianCalendar(zone, aLocale); }}return cal;
}
Copy the code

You can see that both the abstract product role and the factory role are taken by Calendar, and the concrete product role is taken by a subclass of Calendar

JDBC gets the database connection

MySQL > connect to MySQL

// Load the MySql driver class.forname ("com.mysql.jdbc.Driver");
DriverManager.getConnection("JDBC: mysql: / / 127.0.0.1:3306 / test"."root"."123456");
Copy the code

The Driver class com.mysql.jdbc.driver is first loaded through reflection, and then the connection is fetched through DriverManager

Take a look at the code for com.mysql.jdbc.driver. The main content of this class is static code blocks that are executed as the class loads

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {
    }
    static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!"); }}}Copy the code

Static code block: New a Driver class and register it with the DriverManager Driver management class

public static synchronized void registerDriver(java.sql.Driver driver, DriverAction da) throws SQLException {
    /* Register the driver if it has not already been added to our list */
    if(driver ! = null) { registeredDrivers.addIfAbsent(new DriverInfo(driver, da)); }else {
        throw new NullPointerException();
    }
    println("registerDriver: " + driver);
}
Copy the code

Where registeredDrivers is a CopyOnWriteArrayList object

private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
Copy the code

CopyOnWriteArrayList is a concurrent container provided in Java. It is a thread-safe, lock-free ArrayList that reads and writes by creating a new copy of the underlying array. It is a concurrent strategy for read-write separation. Java in the process of contract awarding and similar containers and CopyOnWriteSet an article CopyOnWriteArrayList: www.cnblogs.com/chengxiao/p…

Again through the DriverManager. GetConnection connection object for the main code is as follows: through the for loop (registeredDrivers) to obtain from the registered driver drive, try to connect, connect successfully

private static Connection getConnection(String url, java.util.Properties info, Class<? >caller) throws SQLException { // ... Omit... println("DriverManager.getConnection(\"" + url + "\")");
    for(DriverInfo aDriver : registeredDrivers) {
        // If the caller does not have permission to load the driver then skip it.
        if(isDriverAllowed(aDriver.driver, callerCL)) {
            try {
                println(" trying " + aDriver.driver.getClass().getName());
                Connection con = aDriver.driver.connect(url, info);
                if(con ! = null) { // Success! println("getConnection returning " + aDriver.driver.getClass().getName());
                    return (con);
                }
            } catch (SQLException ex) {
                if(reason == null) { reason = ex; }}}else {
            println(" skipping: "+ aDriver.getClass().getName()); }} / /... Omit... }Copy the code

The factory role is the DriverManager class, the abstract product role is Connection, and there are many concrete product roles

The LoggerFactory in Logback gets the Logger object

If you look at the getLogger method of the LoggerFactory class, you can see that iloggerFactory.getLogger () is called, where iLoggerFactory is an interface

public static Logger getLogger(String name) {
    ILoggerFactory iLoggerFactory = getILoggerFactory();
    return iLoggerFactory.getLogger(name);
}

public static Logger getLogger(Class clazz) {
    return getLogger(clazz.getName());
}
Copy the code

The iLoggerFactory interface has only one getLogger method

public interface ILoggerFactory {
    Logger getLogger(String var1);
}
Copy the code

View its subclass dependencies

Let’s look at the implementation of ILoggerFactory by subclass LoggerContext

You can see that this is a simple factory pattern in if-else mode

The factory role is a subclass of the iLoggerFactory interface such as LoggerContext, the abstract product role is Logger, and the concrete product role is a subclass of Logger, mainly the NOPLogger and Logger classes

summary

The next chapter introduces factory methods and typical applications

The original article can be found at t.cn/Rs6rkYI

Debug mode + memory analysis


For more, visit my personal blog at laijianfeng.org/

Open the wechat scan, follow the wechat official account of “Xiao Xiao Xiao Feng”, and timely receive the blog push