Detailed explanation of Java factory pattern

Factory Method

There are three factory method modes:

General factory mode

It is to create a factory class and create instances of some classes that implement the same interface.

First look at the diagram below:

Examples are as follows: (let's give an example of sending email and SMS)

First, create a common interface between the two:

public interface Sender {  
    public void Send();  
}  

Secondly, create an implementation class:

public class MailSender implements Sender {  
    @Override  
    public void Send() {  
        System.out.println("this is mailsender!");  
    }  
}  
public class SmsSender implements Sender {  
    @Override  
    public void Send() {  
        System.out.println("this is sms sender!");  
    }  
}  

Finally, plant construction:

public class SendFactory {  
  
    public Sender produce(String type) {  
        if ("mail".equals(type)) {  
            return new MailSender();  
        } else if ("sms".equals(type)) {  
            return new SmsSender();  
        } else {  
            System.out.println("Please enter the correct type!");  
            return null;  
        }  
    }  
}  

Let's test:

public class FactoryTest {  
  
    public static void main(String[] args) {  
        SendFactory factory = new SendFactory();  
        Sender sender = factory.produce("sms");  
        sender.Send();  
    }  
}  

Output: this is sms sender!

Multiple factory method patterns

It is an improvement of the ordinary factory method mode. In the ordinary factory method mode, if the string passed is wrong, the object cannot be created correctly, while multiple factory method modes provide multiple factory methods to create objects respectively. Diagram:

Modify the above code and change the SendFactory class as follows:

public class SendFactory {  
    public Sender produceMail(){  
        return new MailSender();  
    }  
    public Sender produceSms(){  
        return new SmsSender();  
    }  
}  

The test classes are as follows:

public class FactoryTest {  
  
    public static void main(String[] args) {  
        SendFactory factory = new SendFactory();  
        Sender sender = factory.produceMail();  
        sender.Send();  
    }  
}  

Output: this is mailsender!

Static factory method mode

Set the methods in the above multiple factory method patterns as static. You can call them directly without creating an instance.

public class SendFactory {  
      
    public static Sender produceMail(){  
        return new MailSender();  
    }  
      
    public static Sender produceSms(){  
        return new SmsSender();  
    }  
}  
public class FactoryTest {  
  
    public static void main(String[] args) {      
        Sender sender = SendFactory.produceMail();  
        sender.Send();  
    }  
}  

Output: this is mailsender!

Generally speaking, the factory pattern is suitable: when a large number of products need to be created and have common interfaces, they can be created through the factory method pattern. In the above three modes, the first one cannot create objects correctly if the incoming string is incorrect. Compared with the second one, the third one does not need an instance factory class. Therefore, in most cases, we will choose the third one - static factory method mode.

Abstract Factory pattern

A problem with the factory method pattern is that the creation of classes depends on factory classes, that is, if you want to expand the program, you must modify the factory class, which violates the closure principle. Therefore, from the design point of view, there are certain problems. How to solve them? The abstract factory pattern is used to create multiple factory classes. In this way, once new functions need to be added, new factory classes can be added directly without modifying the previous code. Because the abstract factory is not easy to understand, let's look at the diagram first, and then compare it with the code, which is easier to understand.

Take an example:

public interface Sender {  
    public void Send();  
}  

Two implementation classes:

public class MailSender implements Sender {  
    @Override  
    public void Send() {  
        System.out.println("this is mailsender!");  
    }  
}  
public class SmsSender implements Sender {  
  
    @Override  
    public void Send() {  
        System.out.println("this is sms sender!");  
    }  
}  

Two factory classes:

public class SendMailFactory implements Provider {  
      
    @Override  
    public Sender produce(){  
        return new MailSender();  
    }  
}  
public class SendSmsFactory implements Provider{  
  
    @Override  
    public Sender produce() {  
        return new SmsSender();  
    }  
}  

When providing an interface:

public interface Provider {  
    public Sender produce();  
}  

Test class:

public class Test {  
  
    public static void main(String[] args) {  
        Provider provider = new SendMailFactory();  
        Sender sender = provider.produce();  
        sender.Send();  
    }  
}  

In fact, the advantage of this mode is that if you want to add a function: sending timely information, you only need to make an implementation class to implement the Sender interface and a factory class to implement the Provider interface. It's OK without changing the ready-made code. In this way, the expansibility is better!

reference

  • https://blog.csdn.net/llussize/article/details/80276627

Tags: Java Back-end

Posted on Sun, 24 Oct 2021 21:21:09 -0400 by kamy99