After coding for a period of time, I have a new understanding of framework and library, so I plan to learn framework and library again.

To return to the Servlet

At that time, I thought the console was boring and not as vivid as the animated desktop. At first, I planned to learn Swing, but later I found it was a little ugly. Later, I found that the market of Java was on the WEB side, that is, the browser. Then you start learning JavaScript, CSS, HTML, Jquery. After learning these three, I still didn’t feel the use of Java. At that time, I was wondering how to put the value of the input box in the browser into Java. The answer is servlets, the bridge between the browser and the server. Something like this:And then once we get the value, we still usually need to store it, which is when we’re dealing with a database, which is JDBC, and it turns out that some of the STEPS in JDBC are repetitive, so we don’t have to repeat it every time we’re dealing with a database, which is DBUtils. This seems to be a complete process of receiving data from the page, storing it in the database, and then requesting it from the page and returning it to the database. However, this process is not perfect. The first is the cooperation between Java and the database. Every TIME YOU send an SQL statement, you create a new connection, which consumes resources. Back then, maven wasn’t used much, dealing with dependencies, and there were always jar packages to paste in the lib directory. A data processing chain at that time looked something like this:And then pretty quickly we started writing more and more code, so we just started dividing the structure, which is MVC, and the top graph was cut into something like this:View is the view layer provided to the user, for the user to operate, is the program shell. The Controller selects the corresponding model according to the user’s input instructions, reads it, and then performs corresponding operations to return it to the user. The three layers are closely linked but independent of each other, and changes within each layer do not affect the other layers. Each layer provides interfaces for the upper layer to call. In this way, the software can be modularized, and the appearance and data changes need not be changed in other layers, which greatly facilitates the maintenance and upgrade of the software. But it’s not perfect, and now the structure of our code is clear. One of the goals of software design is to write less code, and native JDBC is still a bit cumbersome, so can we take it one step further and make it simpler? This is the question raised by many Java developers. The answer is ORM(Object Relational Mapping) framework, and the representative ones are MyBatis and Hibernate. This is reducing the amount of code in the model layer, but integration of THE ORM framework, connection pooling, or coding is currently dependent on the level of the coder. Now after the framework we introduced, the relationship between the frameworks we introduced becomes the following:This might seem like a neat structure, but it’s not what we’re looking for, because typically a WEB project doesn’t introduce just one framework, we introduce other frameworks over and over, such as a timed task framework, a logging framework, a monitoring framework, a permission control framework. Something like this:Chaos and disorder, perhaps a utility class for each framework that encapsulates common methods. But this is not the goal we want, because the code is not invariable, ORM framework, for example, you may at the time of integration and database connection pool is a version, but later discovered to upgrade, this time if you are hard coded, you have to get the code, may also need to contemplate, so we can work hard coded? Manage the dependencies between these frameworks in a unified manner and make them configurable.

This is the factory pattern, the predecessor of Spring, but Spring is not just a factory pattern.

How to select objects – IOC and DI introduction

In the Java world, the main way we get objects is new, which is fine for simple objects. But some objects are more complex to create, and we want to hide those details. Again, we want to hide these details from the user of the object. This is one of the main purposes for the framework to adopt the factory pattern. Let’s take a look at the factory in MyBatis:SqlSession = SqlSessionFactory = SqlSessionFactory = SqlSessionFactory = SqlSessionFactory This is a typical application scenario of the factory pattern. The World of Java is the world of objects, and a lot of our focus is on creating and using objects. If you want to use a HashMap, you don’t have to use design patterns, you can just use new. But not all objects are as simple as a HashMap. Before I was familiar with the design pattern and the Spring framework, I did not use the Spring framework. When the Service layer called the Dao layer, I still used new. Every method of the Service called Dao through new. That’s the singleton pattern. If you don’t understand the singleton pattern, check out this blog post:Today we’ll talk about singleton patterns and enumerations

So what is our vision at this point? In the object-oriented world, we are mainly concerned with fetching (creating) objects and storing them, just like data structures, we are mainly concerned with how to store them and how to retrieve them. The objects created also have different scenarios. Some of the objects we mentioned above are more complex to create, and we want to shield those details from the users of the objects. Scenarios like this are common in Java, such as thread pool creation:It is not recommended to create thread pools this way directly. Then there is also extensibility design. For example, at the beginning, I defined an object, and put the corresponding operation methods of the object into an interface. This is the object-oriented design concept, and use the interface for what we do and the object for what we do. However, with the development, the original object can no longer meet my requirements, but this object is attached to a kind of library, and the actual entity corresponding to the original object is still in use. For forward compatibility, I have to create another class, and the previous operations are still common. As a typical example, Java’s POI library is used to manipulate Excel. There are several versions of Excel. Excel 2003 is *.xls, and Excel 2007 and above is *.xlsx. The maximum number of lines in Excel 2003 is 65536 lines, which sometimes cannot meet the demand. In 2007 version, the maximum number is 1048576 lines, which exceeds 65536 lines. The POI also takes this into account, and is highly extensible. It abstracts the operations on Excel into workbook, and puts the operations specific to a certain version into the corresponding Excel class, like the following:HSSFWorkbook corresponds to version 03, Xssfworkbook corresponds to version 07, SXSSFWorkbook is introduced to solve memory overflow of reading large Excel data. Most of the time, we’re actually going to use the workbook method, there’s no need to look at what version of Excel we’re reading, that’s what WorkbookFactory is all about. You read a file and you need a file object, you give me that file object, and I’ll give you the workbook object.The more abstract description here is that instead of passing new, you use this object to pass the identifier to the factory, which returns the corresponding object. This is the simple factory pattern. A lot of blogs or videos on simple factory patterns (getting started with the Spring framework or design patterns) usually start from a decoupling perspective, and when I watch videos or blogs, one of the questions in my mind is, who are you coupling to whom? If you look at the WorkbookFactory above, Instead of this simple factory pattern, I assume that coders who want to use WorkBook objects are coupled to specific Excel versions of their classes, as follows:

public class ExcelDemo {
    public static void main(String[] args) throws IOException {
        XSSFWorkbook xssfWorkbook = new XSSFWorkbook("");
        HSSFWorkbook hssfWorkbook = new HSSFWorkbook();
        SXSSFWorkbook sxssfWorkbook = newSXSSFWorkbook(); }}Copy the code

At the beginning of Excel import, I first went to find the corresponding class according to Excel version, and then did the data reading work. After writing it, I thought about it. Doesn’t that force users to upload versions of Excel? Suppose the user uploaded a different version, should I give an exception? That seems a little unfriendly, because Excel 03 is still being used. I thought about it and changed my code to look like this:

 public void uploadExcel(MultipartFile file) throws IOException {
        Workbook workbook = null;
        if (file.getName().endsWith(".xls")){
             workbook = new HSSFWorkbook(file.getInputStream());
        }else if (file.getName().endsWith(".xlsx")){
             workbook = new XSSFWorkbook(file.getInputStream());
        }
        // Do real business processing
    }
Copy the code

In this way, my code was uncoupled from the Excel version uploaded by the user, and I could import any version uploaded by the user. At that time, I did not know the factory mode, but subconsciously fulfilled the requirements, so that the excel version uploaded was not limited. Then one day I came across the WorkbookFactory class, which decouples the WorkBook object from the concrete Excel version file object. To demonstrate the above factory pattern in code:

public interface   AnimalBehavior {
    /** * All animals sleep */
    void sleep(a);
    /** ** all have dinner */
    void eat(a);
}
public class Cat implements AnimalBehavior {
    @Override
    public void sleep(a) {
        System.out.println("I'm a cat. I like to sleep.");
    }

    @Override
    public void eat(a) {
        System.out.println("I'm a cat. I like fish."); }}public class Dog implements  AnimalBehavior {
    @Override
    public void sleep(a) {
        System.out.println("I'm a dog. I like to sleep in a kennel.");
    }

    @Override
    public void eat(a) {
        System.out.println("I'm a dog. I like to chew bones."); }}public class AnimalBehaviorFactory {

    public static AnimalBehavior create(String name){
        AnimalBehavior animalBehavior = null;
        if ("dog".equals(name)){
            animalBehavior = new Dog();
        }else if ("cat".equals(name)){
            animalBehavior = new Cat();
        }
        returnanimalBehavior; }}public class Test {
    public static void main(String[] args) {
        AnimalBehavior dog = AnimalBehaviorFactory.create("dog");
        dog.eat();
        AnimalBehavior cat = AnimalBehaviorFactory.create("cat"); cat.eat(); }}Copy the code

When I first started learning the simple factory model, someone wrote an example of this and told me it was called decoupling, and I thought, what is this? I don’t see what’s so great about this design pattern. That’s the design pattern, right? That’s uncoupling, right? Why don’t you tell me who uncoupled who? Is this it? After I learned this thing, I didn’t know how to use it, did I? Even if I explain to people that the simple factory model is this? I feel embarrassed. After writing a little bit of code, after a lot of code, I can give you the answer, which is decoupled from which, the caller of the AnimalBehavior instance is decoupled from the specific animal object (Cat, Dog), just by passing some identifier to the factory, and the factory returns to you the corresponding instance of the AnimalBehavior, You can also mask the complex details of object creation. The actual usage scenario is the WorkBookFactory of the POI. We have covered the simple factory pattern. I will not draw UML diagrams here, because I think some of you may not be able to read UML diagrams (there will be a special article on UML later). On the other hand, I think my presentation is clear enough.

In the object-oriented world, all we care about is taking objects, simpler, simpler. For example, our ORM framework MyBatis relies on connection pool, and connection pool depends on the corresponding database driver. Therefore, creating a SqlSession object is the creation and injection of a group of objects. Go to New by yourself? Is this one in trouble? Can it be managed uniformly? Because someday I might change the connection pool? This is the Spring IOC idea. You put objects into the IOC container, configure their dependencies, and then the IOC container helps you new. You just need to fetch.

Another situation is when you know how to create an object, but have no control over when, so you have to shove the “how” code into the “when” code. The latter, where appropriate, calls the corresponding function that creates the object.

In addition, constructors in languages such as C++ are not allowed to throw exceptions, as this will result in an object that is not fully constructed, resulting in the corresponding memory being improperly freed. In Java, throwing exceptions in constructors is supported by the language, but it is not recommended. Since it is not the subject of this article, we will not discuss it here. See this blog for details:

  • [Improving Java code] Do not throw exceptions in constructors

But the business requires that when we create an object, we throw an exception, how do we handle that, we can also use the factory pattern, not necessarily the simple factory pattern above, but this is also an application of the factory pattern idea.

The essence of factory pattern is to abstract the process of acquiring objects, so the factory method pattern and abstract factory pattern introduced next will be relatively abstract, we need to slowly understand the benefits of these two design patterns, need a certain amount of code to understand.

Factory method pattern

The Factory Method pattern, in which the core Factory class is no longer responsible for all product creation, passes the specific creation work to subclasses. This core class, called an abstract factory role, is only responsible for giving the interfaces that a concrete factory subclass must implement, without touching the details of which product class should be instantiated. Using the above example, we can convert to the following:

// Define the top-level core factory class
public interface AbstractAnimalFactory {
    AnimalBehavior  getBehavior(a);
}
// The specific subclass is responsible for the corresponding creation
public class CatFactory implements  AbstractAnimalFactory {
    @Override
    public AnimalBehavior getBehavior(a) {
        return newCat(); }}public class DogFactory implements AbstractAnimalFactory {
    @Override
    public AnimalBehavior getBehavior(a) {
        return newDog(); }}public class Test {
    public static void main(String[] args) {
        AbstractAnimalFactory abstractAnimalFactory = newDogFactory(); AnimalBehavior dog = abstractAnimalFactory.getBehavior(); dog.eat(); }}Copy the code

The nice thing is, instead of hard coding, let’s say that in the factory mode above, we want to add a pig object, and then the simple factory above has to be changed, requiring another judgment. We don’t want to touch old code, and even if you modify it carefully, it’s not foolproof. So for this factory approach pattern, we just need to add a pig factory, composite design principle, closed for modification, open for addition. Add another pig farm:

public class Pig implements  AnimalBehavior {
    @Override
    public void sleep(a) {
        System.out.println("The pig is sleeping.");
    }

    @Override
    public void eat(a) {
        System.out.println("Pigs eat everything."); }}public class PigFactory implements  AbstractAnimalFactory {
    @Override
    public AnimalBehavior getBehavior(a) {
        return newPig(); }}Copy the code

Abstract Factory pattern

The essence of the factory pattern is an abstraction of the process of obtaining objects, and again, not one abstraction can be used for all object creation scenarios, because you can see different scenarios from different perspectives. From many blogs for the realization of the abstract factory pattern, relative to the factory method pattern, the core of the top factory is no longer just a method, the core of the top factories will appear several abstract method, which is the core of the top factories can produce objects are products of the gens, each factory production of products is also has more than one, an example of this is common in the real world, Xiaomi, for example, makes not only phones but also homes and laptops. Not only Xiaomi, But Apple also makes smart homes and computers.

From this perspective, the factory method pattern is more like a watered down version of the abstract factory pattern. First of all, we prepare two types of products. The first is the mobile phone interface, which describes the specifications for the production of mobile phones; the second is the PC interface, which describes the specifications for the production of PC. You can certainly use other examples, such as high-end masks and low-end masks, but ultimately the message is the same.

public interface PersonalComputer {
    // Know the computer
    void makePc(a);
}
public interface Phone {
   // Make mobile phones
   void makePhone(a);
}
Copy the code

Then here’s the core factory:

public interface AbstractEmFactory {
    PersonalComputer createPersonalComputer(a);
    Phone createPhone(a);
}
Copy the code

Then there is the factory that produces the product:

public class MiEmFactory implements AbstractEmFactory {
    @Override
    public PersonalComputer createPersonalComputer(a) {
        return new MiPC();
    }

    @Override
    public Phone createPhone(a) {
        return newMiPhone(); }}public class OppoEmFactory implements AbstractEmFactory {
    @Override
    public PersonalComputer createPersonalComputer(a) {
        return new OppoPC();
    }

    @Override
    public Phone createPhone(a) {
        return newOppoPhone(); }}Copy the code

The test class:

public class Test {
    public static void main(String[] args) {
        OppoEmFactory oppoEmFactory = newOppoEmFactory(); PersonalComputer personalComputer = oppoEmFactory.createPersonalComputer(); personalComputer.makePc(); Phone oppoPhone = oppoEmFactory.createPhone(); oppoPhone.makePhone(); }}Copy the code

Compared to the factory method pattern, the advantage of the abstract factory method pattern is that there is no need to have more categories of products, WE can have a factory to manufacture it, we can classify them into a family according to the characteristics, which also reduces the factory subclass, easier to maintain.

To summarize

Factory pattern is not an independent design pattern, but the general name of three design patterns with similar functions, which are simple factory pattern, factory method pattern and abstract factory pattern. In fact, the book zen of Design Patterns is divided into two chapters on factory patterns. We do not separate out the simple factory patterns mentioned above, but count the simple factory patterns mentioned above in the factory method patterns. But most of the data up here divide factory models into three categories:

  • Simple/static factory mode
  • Factory method pattern
  • Abstract Factory pattern

In the Effective Java, the author advocates the use of static factory pattern instead of the constructor, why the advocate, the advocate is based on the premise that you have more than one constructor, we know that the constructor is we have no way to change name, we can see know righteousness principle to invoke the object’s man exposed more information? That is, to tell the caller what object is being produced. This is another use scenario for the static factory pattern.

Let’s look at the simple factory pattern, the factory method pattern, and the abstract factory pattern. The common goal is to make it easier for callers to get their hands on the objects they need to use, that is, to decouple, and to centralize management. What we want to do is make it as easy as possible for people who are using objects to get the objects they want to use, rather than just trying to find the class and use constructors to generate it. In an object-oriented world, where objects are everywhere, generalize objects as much as possible, and gather them up, that’s what the factory model is trying to do.

The simple factory pattern returns the corresponding object to the caller based on the identifier passed by the caller, decoupling the caller from the actual class but not following the open-closed principle (closed for modification, open for addition). If I wanted one more class, then the simple factory pattern would probably require one more judgment. The advantage is that compared to the factory method pattern, we don’t need to know the corresponding factory. But we remember not to copy mechanically, just use a certain type of mode, according to the situation to use a combination. The factory method pattern compounds the open close principle, but it is up to the caller to try to understand the corresponding factory to produce the corresponding object. So as the grow in quantity of products, this can only be for the production of a product soon can’t meet the needs of our factory, because each product needs to be a factory, so many factory for maintenance is also a burden, we will according to the characteristics of the product they are divided into, the abstract factory production is gens products.

There is no perfect design mode, and no design mode is suitable for all situations. We need to choose the corresponding mode according to the actual situation, but we can also transform the corresponding design mode in practice, so as to achieve the best decoupling effect. For example, the WorkbookFactory class was not originally added to the POI, but was introduced in version 4.0.

It doesn’t matter what language you use, what resources you create. You’re using factory mode when you start writing code for the Create itself.

References:

  • Talk about MVC model Ruan Yifeng
  • What is the nature of the Factory Method? Why introduce the factory pattern?
  • Spring video tutorial Yan Qun
  • Comics: “Factory Mode” design Patterns
  • Do you understand the factory model?
  • Why can’t C++ constructors throw exceptions
  • Factory Patterns for Design Patterns