Thoroughly explain the details of the simple factory that you haven't paid attention to

Keywords: Java Design Pattern architecture

This article is excerpted from "design patterns should be learned this way"

1 encapsulate product creation details using simple factory mode

Next, let's look at the code and take the creation of an online course as an example. Assuming that there are courses such as Java architecture, big data and artificial intelligence, an ecosystem has been formed. We can define a course standard ICourse interface.

public interface ICourse {
    /** record video  */
    public void record();
}

Create a Java course implementation class JavaCourse.

public class JavaCourse implements ICourse {
    public void record() {
        System.out.println("Recording Java curriculum");
    }
}

The client call code is as follows.

public static void main(String[] args) {
    ICourse course = new JavaCourse();
    course.record();
}

It can be seen from the above code that the parent class ICourse refers to the subclass JavaCourse, and the application layer code needs to rely on JavaCourse. If the business expands, continue to add Python course or even more, and the dependence of the client will become more and more bloated. Therefore, we should find a way to weaken this dependence and hide the creation details. Although in the current code, the process of creating objects is not complex, it is not easy to expand from the perspective of code design. Therefore, the code is optimized with the simple factory pattern. First, add the course Python course class.

public class PythonCourse implements ICourse {
    public void record() {
        System.out.println("Recording Python curriculum");
    }
}

Then create the CourseFactory factory class.

public class CourseFactory {
    public ICourse create(String name){
        if("java".equals(name)){
            return new JavaCourse();
        }else if("python".equals(name)){
            return new PythonCourse();
        }else {
            return null;
        }
    }
}

Finally, modify the client call code.

public class SimpleFactoryTest {
    public static void main(String[] args) {
        CourseFactory factory = new CourseFactory();
        factory.create("java");
    }
}

Of course, for the convenience of calling, you can change the create() method of CourseFactory into a static method, and its class diagram is shown in the following figure.

Although the client call is simple, if the business continues to expand and the front-end courses need to be added, the create() method in the factory needs to modify the code logic every time with the enrichment of the product chain, which does not comply with the opening and closing principle. Therefore, we can continue to optimize the simple factory mode by using reflection technology. The code is as follows.

public class CourseFactory {
    public ICourse create(String className){
        try {
            if (!(null == className || "".equals(className))) {
                return (ICourse) Class.forName(className).newInstance();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}

The client call code is modified as follows.

public static void main(String[] args) {
        CourseFactory factory = new CourseFactory();
        ICourse course = factory.create("com.gupaoedu.vip.pattern.factory.simplefactory.JavaCourse");
        course.record();
}

After optimization, the products are constantly enriched, and there is no need to modify the code in CourseFactory. However, the problem is that the method parameters are strings, the controllability needs to be improved, and forced transformation is needed. Continue to modify the code.

public ICourse create(Class<? extends ICourse> clazz){
    try {
        if (null != clazz) {
            return clazz.newInstance();
        }
    }catch (Exception e){
        e.printStackTrace();
    }
    return null;
}

Optimize client test code.

public static void main(String[] args) {
    CourseFactory factory = new CourseFactory();
    ICourse course = factory.create(JavaCourse.class);
    course.record();
}

Finally, let's look at the class diagram shown in the figure below.

2 Application of simple factory mode in JDK source code

The simple factory pattern is ubiquitous in the JDK source code. For example, the Calendar class, see the Calendar.getInstance() method. The following opens the specific creation class of Calendar.

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;
}

3 application of simple factory mode in Logback source code

In the Logback we often use, we can see that there are multiple overloaded methods getLogger() in LoggerFactory.

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

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

[recommendation] Tom bomb architecture: collecting this article is equivalent to collecting a book on "design patterns"

This article is the original of "Tom bomb architecture". Please indicate the source for reprint. Technology lies in sharing, I share my happiness!
If this article is helpful to you, you are welcome to pay attention and praise; If you have any suggestions, you can also leave comments or private letters. Your support is the driving force for me to adhere to my creation. Focus on WeChat official account Tom structure, get more dry cargo!

Posted by SieRobin on Tue, 09 Nov 2021 23:08:46 -0800