Starting again in 2020, the fourth of JAVA design patterns is the abstract factory pattern

Abstract factory pattern (detailed version)

The production of a kind of products is considered in the factory method mode, such as only raising animals in the livestock ranch, only producing televisions in the TV factory, and only cultivating students majoring in computer software in the school of computer software.

The same kind is called the same grade, that is to say: the factory method mode only considers the production of products of the same grade, but in real life, many factories are comprehensive factories, which can produce products of multiple grades (types), such as raising animals and plants on farms, producing televisions and washing machines or air conditioners in electrical factories, and both software and biology majors in universities.

The abstract factory model will consider the production of multi-level products. A group of products at different levels produced by the same specific factory is called a product family. Figure 1 shows the corresponding relationship between televisions and air conditioners produced by Haier factory and TCL factory.

​ Figure 1 product grade and product family of Electrical Factory

Definition and characteristics of pattern

Definition of abstract factory pattern: it is a pattern structure that provides an interface for an access class to create a group of related or interdependent objects, and the access class can obtain different levels of products of the same family without specifying the specific class of the product.

Abstract factory pattern is an upgraded version of factory method pattern. Factory method pattern only produces one level of products, while abstract factory pattern can produce multiple levels of products.

The following conditions are generally met when using the abstract factory pattern.

  • There are multiple product families in the system. Each specific factory creates products of the same family but belonging to different hierarchical structures.
  • The system can only consume one family of products at a time, that is, the products of the same family can be used together.

In addition to the advantages of the factory method pattern, the abstract factory pattern has the following main advantages.

  • The multi-level products associated in the product family can be managed together within the class, instead of introducing multiple new classes for management.
  • When a new product family needs to be modified, a new product family needs to be added.

The disadvantage is that when a new product needs to be added to the product family, all factory classes need to be modified.

Structure and implementation of pattern

Abstract factory mode, like factory method mode, is also composed of four elements: abstract factory, concrete factory, abstract product and concrete product. However, the number of methods in abstract factory is different, so is the number of abstract products. Now let's analyze its basic structure and implementation method.

Structure of pattern

The main roles of the abstract factory pattern are as follows.

  1. Abstract Factory: it provides an interface for creating products. It contains multiple methods for creating products, newProduct(), which can create multiple products of different levels.
  2. Concrete Factory: it mainly implements multiple abstract methods in the abstract factory to complete the creation of specific products.
  3. Abstract Product: it defines the specification of the Product and describes the main characteristics and functions of the Product. The abstract factory pattern has multiple Abstract products.
  4. Concrete product: it implements the interface defined by the abstract product role and is created by the concrete factory. It has a many to one relationship with the concrete factory.

The structure diagram of the abstract factory pattern is shown in Figure 2.

​ Figure 2 structure diagram of abstract factory pattern

Implementation of pattern

As can be seen from Figure 2, the structure of the abstract factory pattern is similar to that of the factory method pattern. The difference is that there are more than one product type, so there are more than one method to create products. The code of abstract factory and concrete factory is given below.

(1) Abstract factory: provides the generation method of products.

interface AbstractFactory{    
    public Product1 newProduct1();    
    public Product2 newProduct2();
}

(2) Specific factory: the product generation method is realized.

class ConcreteFactory1 implements AbstractFactory{    
    public Product1 newProduct1()    {        
        System.out.println("Specific factory 1 generation-->Specific products 11...");       
        return new ConcreteProduct11();    
    }    
    
    public Product2 newProduct2()    {        
        System.out.println("Specific factory 1 generation-->Specific products 21...");        
        return new ConcreteProduct21();    
    }
}

Application examples of pattern

Designing farm class with abstract factory pattern

Analysis: in addition to raising animals like livestock farms, farms can also cultivate plants, such as raising horses, cattle, vegetables, fruits, etc. Therefore, this example is more complex than the livestock farms described above, and must be realized by abstract factory mode.

This example uses the abstract factory model to design two farms, one is Shaoguan farm for raising cattle and vegetables, and the other is Shangrao farm for raising horses and fruits. In the above two farms, you can define a method newAnimal() for generating animals and a method newPlant() for cultivating plants.

For specific products such as horses, cattle, vegetables and fruits, their images should be displayed( Click here to download pictures )Therefore, JPanel, JLabel, ImageIcon and other components are used in their constructors, and a show() method is defined to display them.

The client program reads the data in the XML configuration file through the object generator class ReadXML to decide what animals and plants to raise( Click here to download the XML file ). Its structure is shown in Figure 3.

​ Figure 3 structure of farm

The program code is as follows:

package AbstractFactory;
import java.awt.*;
import javax.swing.*;
public class FarmTest
{
    public static void main(String[] args)
    {
        try
        {          
            Farm f;
            Animal a;
            Plant p;
            f=(Farm) ReadXML.getObject();
            a=f.newAnimal();
            p=f.newPlant();
            a.show();
            p.show();
        }
        catch(Exception e)
        {
            System.out.println(e.getMessage());
        }
    }
}
//Abstract products: Animals
interface Animal
{
    public void show();
}
//Specific products: Horses
class Horse implements Animal
{
    JScrollPane sp;
    JFrame jf=new JFrame("Abstract factory pattern testing");
    public Horse()
    {
        Container contentPane=jf.getContentPane();
        JPanel p1=new JPanel();
        p1.setLayout(new GridLayout(1,1));
        p1.setBorder(BorderFactory.createTitledBorder("Animal: Horse"));
        sp=new JScrollPane(p1);
        contentPane.add(sp, BorderLayout.CENTER);
        JLabel l1=new JLabel(new ImageIcon("src/A_Horse.jpg"));
        p1.add(l1);       
        jf.pack();       
        jf.setVisible(false);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//The user clicks the window to close 
    }
    public void show()
    {
        jf.setVisible(true);
    }
}
//Specific products: Cattle
class Cattle implements Animal
{
    JScrollPane sp;
    JFrame jf=new JFrame("Abstract factory pattern testing");
    public Cattle() {
        Container contentPane=jf.getContentPane();
        JPanel p1=new JPanel();
        p1.setLayout(new GridLayout(1,1));
        p1.setBorder(BorderFactory.createTitledBorder("Animal: Cattle"));
        sp=new JScrollPane(p1);
        contentPane.add(sp, BorderLayout.CENTER);
        JLabel l1=new JLabel(new ImageIcon("src/A_Cattle.jpg"));
        p1.add(l1);       
        jf.pack();       
        jf.setVisible(false);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//The user clicks the window to close 
    }
    public void show()
    {
        jf.setVisible(true);
    }
}
//Abstract products: Plants
interface Plant
{
    public void show();
}
//Specific products: Fruits
class Fruitage implements Plant
{
    JScrollPane sp;
    JFrame jf=new JFrame("Abstract factory pattern testing");
    public Fruitage()
    {
        Container contentPane=jf.getContentPane();
        JPanel p1=new JPanel();
        p1.setLayout(new GridLayout(1,1));
        p1.setBorder(BorderFactory.createTitledBorder("Plant: Fruit"));
        sp=new JScrollPane(p1);
        contentPane.add(sp, BorderLayout.CENTER);
        JLabel l1=new JLabel(new ImageIcon("src/P_Fruitage.jpg"));
        p1.add(l1);       
        jf.pack();       
        jf.setVisible(false);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//The user clicks the window to close 
    }
    public void show()
    {
        jf.setVisible(true);
    }
}
//Specific products: Vegetables
class Vegetables implements Plant
{
    JScrollPane sp;
    JFrame jf=new JFrame("Abstract factory pattern testing");
    public Vegetables()
    {
        Container contentPane=jf.getContentPane();
        JPanel p1=new JPanel();
        p1.setLayout(new GridLayout(1,1));
        p1.setBorder(BorderFactory.createTitledBorder("Plant: Vegetable"));
        sp=new JScrollPane(p1);
        contentPane.add(sp, BorderLayout.CENTER);
        JLabel l1=new JLabel(new ImageIcon("src/P_Vegetables.jpg"));
        p1.add(l1);       
        jf.pack();       
        jf.setVisible(false);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//The user clicks the window to close 
    }
    public void show()
    {
        jf.setVisible(true);
    }
}
//Abstract factory: Farm class
interface Farm
{
    public Animal newAnimal();
    public Plant newPlant();
}
//Specific factory: Shaoguan farm
class SGfarm implements Farm
{
    public Animal newAnimal()
    {
        System.out.println("A new cow is born!");
        return new Cattle();
    }
    public Plant newPlant()
    {
        System.out.println("Vegetables grow!");
        return new Vegetables();
    }
}
//Specific factory: Shangrao farm
class SRfarm implements Farm
{
    public Animal newAnimal()
    {
        System.out.println("The new horse was born!");
        return new Horse();
    }
    public Plant newPlant()
    {
        System.out.println("Fruit grows!");
        return new Fruitage();
    }
}
package AbstractFactory;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import java.io.*;
class ReadXML
{
    public static Object getObject()
    {
        try
        {
            DocumentBuilderFactory dFactory=DocumentBuilderFactory.newInstance();
            DocumentBuilder builder=dFactory.newDocumentBuilder();
            Document doc;                           
            doc=builder.parse(new File("src/AbstractFactory/config.xml"));
            NodeList nl=doc.getElementsByTagName("className");
            Node classNode=nl.item(0).getFirstChild();
            String cName="AbstractFactory."+classNode.getNodeValue();
            System.out.println("New class name:"+cName);
            Class<?> c=Class.forName(cName);
              Object obj=c.newInstance();
            return obj;
        }  
        catch(Exception e)
        {
               e.printStackTrace();
               return null;
        }
    }
}

​ The running results of the program are shown in Figure 4.

​ Figure 4 operation results of farm breeding

Application scenario of pattern

The earliest application of abstract factory pattern is to create Windows components belonging to different operating systems. The local implementation of components such as Button and Text in AWT of java is different in Windows and UNIX.

The abstract factory pattern is generally applicable to the following scenarios:

  1. When the objects to be created are a series of interrelated or interdependent product families, such as televisions, washing machines, air conditioners, etc.
  2. There are multiple product families in the system, but only one of them is used at a time. If someone only likes to wear clothes and shoes of a certain brand.
  3. The class library of products is provided in the system, and the interfaces of all products are the same. The client does not depend on the creation details and internal structure of product instances.

Mode extension

The extension of abstract factory mode has a certain inclination of "opening and closing principle":

  1. When adding a new product family, you only need to add a new specific factory without modifying the original code to meet the opening and closing principle.
  2. When a new type of product needs to be added to the product family, all factory classes need to be modified, which does not meet the opening and closing principle.

On the other hand, when there is only one hierarchical product in the system, the abstract factory pattern will degenerate to the factory method pattern.

Tags: Java Design Pattern

Posted by @sh on Sun, 15 May 2022 08:08:21 +0300