Design pattern (simple factory pattern) -- the basis of Java programming

Keywords: Java UML

1, Definition

Design pattern: software pattern is to apply the general concept of pattern to the field of software development, that is, the overall guiding idea or reference template of software development. Software patterns are not limited to design patterns, but also include architecture patterns, analysis patterns and process patterns. In fact, there are some recognized patterns at each stage of software life.

2, At present, there are three main design modes:

(1) Classification by creation mode:

1. Simple Factory Pattern

2. Factory Method Pattern

3. Abstract factory pattern

4. Builder mode

5. Singleton mode

(2) Classification by structural pattern

1. Adapter mode

2. Bridging mode

3. Decoration mode

4. Appearance mode

5. Yuan sharing mode

6. Agency mode

  (3) Classification by behavioral pattern

1. Command mode

2. Intermediary model

3. Observer mode

4. Status mode

5. Strategy mode

3, Simple factory mode

An example is given to illustrate the interface, simple factory mode and control inversion IOC

  1. Create a new project (project name TestSimplyFactoryModel)

2. Take automobile as an example: automobile can be divided into bus, truck, etc. We define the car as an interface, and the car and truck realize the car interface respectively.

Create a simple factory package:

Enter package name: simpleFactory:

  For convenience, please put the following interfaces and objects into this package.

3. Next, create a car interface:

Define a show method in Car:

4. Next, define two classes to implement the automobile interface, one is the bus class and the other is the truck class. At the same time, rewrite the show method of the interface as follows:

 

Step 1. If the traditional method does not adopt the factory mode, our method of instantiating buses and trucks is as follows:

We create a main class, write code in the main function, instantiate bus objects and truck objects, and output their show() methods: as shown in the following figure:

Save and run the program to view the results:

Step 2. Simple factory mode:

In the above interface development, we need to remember many class names: bus class and truck class. Instantiate them according to their class names, such as:

Note that the above code can be rewritten as:

Car  c1 = new Bus()

Car  c2 = new Truck();

In fact, they all belong to automobile interfaces. Can you unify the methods of instantiating them? Let's rewrite the above code with simple factory mode.

(1) We create a class on the package simpleFactory (used to produce cars, we call it factory class) called CaFactory. (interface inheritance is not required)

In this CarFactory class, we create a method getCar to generate cars, and its return value is the interface Car, as shown in the following code:

package simpleFactory;

public class CarFactory {
    
    public static Car getCar(String type) {
        
         Car carType = null;     //     Define a car first
        
        switch(type)
        {
            case "Bus":
                 carType = new Bus();     //     Production bus
                break;
            
            case "Truck":
                 carType = new Truck();     //     Production truck
                break;
        }
         return carType;     //     Returns the type of car produced
    }

}

}

Above, we put all the work of instantiating the car into this CarFactory class.

(2) Go back to the MainClass class, comment out the previous code in the Main function, and modify the code as follows:

public class MainClass {

  public static void main(String[] args) {

         // Method of factory mode;

        Car c1 = CarFactory.getCar("Bus");
        Car c2 = CarFactory.getCar("Truck");
        c1.show();
        c2.show();

  }

}

Comparison of the two methods:

Note that after using the simple factory pattern, the instantiation adopts the same method to instantiate, only indicating which class it is in the parameters.

Step 3: use reflection

Back to our CarFactory class, we use the switch statement to distinguish each kind of fruit class. If there are many kinds of fruit classes, this writing method is very troublesome.

public class CarFactory {

   public static Car getCar(String type) {

          /* Here, the bytecode of the car subclass is obtained through reflection, that is, the class object. The car subclass is created through the newInstance() method of the class object*/

          Class car = Class.forName(CarFactory.class.getPackage().getName()+"."+type);

       return (Car) carType.newInstance();

      }

}

(here CarFactory.class.getPackage().getName() is used to find the package where CarFactory is located. You can also directly write the name of the package where your car class is located, such as "simFactory." + type)

Then move the mouse over all the codes with wavy lines and click add.throw.declaration

As shown below:

Return to the Main function of the Main class MainClass, move the mouse to the wave line, right-click, and add.throw.declaration

(Note: here, the factory class and the created subclass are placed in the same package CarFactory for easy calling.)

The bytecode of the car subclass, that is, the class object, is obtained through reflection. The car subclass is created through the newInstance() method of the class object.

After saving and running, the result remains unchanged, but the reflection method is adopted here. There is no need to judge how many kinds of cars there are and write the code respectively. However, throw pre error processing should be added here to prevent users from writing the wrong class name and unable to create the corresponding class.

The above simple factory model implements the concept of inversion of control (Ioc), that is, the object creating the class is transferred from bus and truck to CarFactory.

Full code:

public interface Car {
	public void show();

}


public class Bus implements Car{

	public void show() {
		
		System.out.println("This is a bus!");
	}

}


public class Truck implements Car {

	public void show() {
		
		System.out.println("This is a truck!");
	}

}


public class CarFactory {
	
		@SuppressWarnings("deprecation")
	public static Car getCar(String type) throws ClassNotFoundException, InstantiationException, IllegalAccessException { // The method is static and can be accessed directly with the class name without creating an object
		
//      Use reflection
		@SuppressWarnings("rawtypes")
		Class carType = Class.forName(CarFactory.class.getPackage().getName()+"."+type);
		return (Car)carType.newInstance();
		
/*		
        Method of simple factory mode
		switch(type)
		{
			case "Bus":
				carType = new Bus();	//	Production bus
				break;
			
			case "Truck":
				carType = new Truck();	//	Production truck
				break;
		}
		
		return carType;	//	Returns the type of car produced
	
*/
		
	}
}


public class MainClass {

	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
			
/* 
	Traditional methods:
		Bus b = new Bus();		// Instantiate bus object
		Truck t = new Truck();	// Instantiate truck object
		b.show();
		t.show();	
*/		
		
/*	
 	Method of simple factory mode
	   Car c1 = CarFactory.getCar("Bus");
	   Car c2 = CarFactory.getCar("Truck");
	   c1.show();
	   c2.show();
*/		
		
// Use reflection
	   Car c1 = CarFactory.getCar("Bus");
	   Car c2 = CarFactory.getCar("Truck");
	   c1.show();
	   c2.show();
	   
	}

}

example:

Please create a Test project to practice the simple factory mode

Requirement: please define a Fruit interface, which has the method showFruit() to display Fruit. Define several Fruit classes: Apple and banana. Their showFruit method is to display their own Fruit name, and define a Fruit factory class FruitFactory,

Please instantiate an apple object and a banana object with the factory pattern and output their showFruit() methods.

Code example:

public interface Fruit {
	public void showFruilt();
}

public class Apple implements Fruit {

	public void showFruilt() {
		System.out.println("Apple");

	}

}

public class Banana implements Fruit {

	public void showFruilt() {
		System.out.println("Banana");

	}

}

public class FruitFactory {
	
	public static Fruit getFruit(String type) {
		
		Fruit fruitType = null;
		
		switch(type) {
			case "Apple":
				fruitType = new Apple();
				break;
				
			case "Banana":
				fruitType = new Banana();
				break;
		}
		
		return fruitType;
	}
}

public class MainCLass {

	public static void main(String[] args) {
		
		Fruit f1 = FruitFactory.getFruit("Apple");
		Fruit f2 = FruitFactory.getFruit("Banana");
		f1.showFruilt();
		f2.showFruilt();

	}

}

Posted by urgido on Sat, 20 Nov 2021 12:01:13 -0800