Use of factory pattern in java design pattern | use of ordinary factory pattern, multiple factory method pattern, static factory method pattern, abstract factory pattern | advanced use of factory pattern

table of Contents

Factory method pattern (Factory Pattern)

Preface

1. Ordinary factory model

 demo:

operation result: 

    2. Multiple factory method patterns

demo:

 operation result:

    3. Static factory method pattern

demo:

  operation result:

 4. Abstract Factory Mode (Abstract Factory)

demo:

operation result:

Advanced use

1. Judge by if...else...

demo

operation result:

2. Through annotations, aspect programming

demo:

operation result:


 

Factory method pattern (Factory Pattern)

Preface

There are three factory method patterns: ordinary factory pattern, multiple factory method patterns, static factory method patterns

In the factory mode, we do not expose the creation logic to the client when creating an object, and we use a common interface to point to the newly created object

Advantages:  1. A caller wants to create an object, as long as he knows its name. 2. High scalability. If you want to add a product, just extend a factory class. 3. Shield the specific implementation of the product, the caller only cares about the product interface.

Disadvantages: Every time a product is added, a concrete class and object implementation factory need to be added, which doubles the number of classes in the system, which increases the complexity of the system to a certain extent, and at the same time increases the specific class of the system rely. This is not a good thing.

Usage scenarios:  1. Log recorder: Records may be recorded to local hard disks, system events, remote servers, etc. The user can choose where to record the logs. 2. Database access, when the user does not know which type of database the system uses in the end, and the database may change. 3. To design a framework to connect to the server, three protocols are required, "POP3", "IMAP", and "HTTP". These three can be used as product classes to implement an interface together.

Note: As a creation class pattern, the factory method pattern can be used wherever complex objects need to be generated. One thing to note is that complex objects are suitable for using the factory pattern, while simple objects, especially objects that only need to be created through new, do not need to use the factory pattern. If you use the factory pattern, you need to introduce a factory class, which will increase the complexity of the system.

    


1. Ordinary factory model

Is to establish a factory class to create instances of product classes that implement the same interface  

 demo:

//The interface for sending SMS and email

/**
 * Created by yjl on 2020/7/27.
 * 工厂模式之普通工厂模式
 * 工厂模式介绍地址:https://blog.csdn.net/qq_27471405/article/details/107607047
 * 微信公众号:zygxsq
 */
//发送短信和邮件的接口
public interface Sender {
	public void Send();
}


//The implementation class of sending mail

/**
 * Created by yjl on 2020/7/27.
 * 工厂模式之普通工厂模式
 * 工厂模式介绍地址:https://blog.csdn.net/qq_27471405/article/details/107607047
 * 微信公众号:zygxsq
 */
//发送邮件的实现类
public class MailSender implements Sender {
	public void Send() {
		//这里写发送邮件的业务逻辑
		System.out.println("发送邮件!");
	}
}


  
//Implementation class for sending SMS 

/**
 * Created by yjl on 2020/7/27.
 * 工厂模式之普通工厂模式
 * 工厂模式介绍地址:https://blog.csdn.net/qq_27471405/article/details/107607047
 * 微信公众号:zygxsq
 */
//发送短信的实现类
public class SmsSender implements Sender {
	public void Send() {
		//这里写发送短信的业务逻辑
		System.out.println("发送短信!");
	}
}

 

 //Create a factory class

/**
 * Created by yjl on 2020/7/27.
 * 工厂模式之普通工厂模式
 * 工厂模式介绍地址:https://blog.csdn.net/qq_27471405/article/details/107607047
 * 微信公众号:zygxsq
 */
//创建工厂类
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("请输入正确的类型!");
			return null;
		}
	}
}


   //Test class

/**
 * Created by yjl on 2020/7/27.
 * 工厂模式之普通工厂模式
 * 工厂模式介绍地址:https://blog.csdn.net/qq_27471405/article/details/107607047
 * 微信公众号:zygxsq
 */
//测试类
public class FactoryTest {
	public static void main(String[] args) {
		SendFactory factory = new SendFactory();
		Sender sender = factory.produce("mail");
		sender.Send();
	}
}

operation result: 

 


    2. Multiple factory method patterns

It is an improvement to the ordinary factory method pattern. In the ordinary factory method pattern, if the passed string is wrong, the object cannot be created correctly, and the multiple factory method pattern provides multiple factory methods to create objects separately.

    //Modify the above code and change the SendFactory class.//There
    is no need to create an object based on the string class passed by the user.

demo:


  

//Create a factory class

/**
 * Created by yjl on 2020/7/27.
 * 工厂模式之多个工厂方法模式
 * 工厂模式介绍地址:https://blog.csdn.net/qq_27471405/article/details/107607047
 * 微信公众号:zygxsq
 */
//创建工厂类
public class SendFactory {

	public Sender produceMail(){
		return new MailSender();
	}

	public Sender produceSms(){
		return new SmsSender();
	}
}

//Test class 

 

/**
 * Created by yjl on 2020/7/27.
 * 工厂模式之多个工厂方法模式
 * 工厂模式介绍地址:https://blog.csdn.net/qq_27471405/article/details/107607047
 * 微信公众号:zygxsq
 */
//测试类
public class FactoryTest {
	public static void main(String[] args) {
		SendFactory factory = new SendFactory();
		Sender sender = factory.produceMail();
		sender.Send();
	}
}

 operation result:


 

    3. Static factory method pattern

Set the methods in the above multiple factory method patterns as static, without creating an instance, just call it directly.

demo:

 //Create a factory class

/**
 * Created by yjl on 2020/7/27.
 * 工厂模式之静态工厂方法模式
 * 工厂模式介绍地址:https://blog.csdn.net/qq_27471405/article/details/107607047
 * 微信公众号:zygxsq
 */
//创建工厂类
public class SendFactory {

	public static Sender produceMail(){
		return new MailSender();
	}

	public static Sender produceSms(){
		return new SmsSender();
	}
}


  //Test class

/**
 * Created by yjl on 2020/7/27.
 * 工厂模式之静态工厂方法模式
 * 工厂模式介绍地址:https://blog.csdn.net/qq_27471405/article/details/107607047
 * 微信公众号:zygxsq
 */
//测试类
public class FactoryTest {
	public static void main(String[] args) {
		Sender sender = SendFactory.produceMail();
		sender.Send();
	}
}

  operation result:

 



 4. Abstract Factory Mode (Abstract Factory)

One problem with the factory method pattern is that the creation of classes depends on the factory class, that is, if you want to expand the program, you must modify the factory class, which violates the principle of closure. Therefore, from a design perspective, there are certain problems ,How to solve? The abstract factory pattern is used to create multiple factory classes, so that once new functions need to be added, a new factory class can be added directly without modifying the previous code. 

demo:

   

Disassemble the previous creation factory class and use subclasses of the abstract class to create different factory classes

//Create an interface for the factory class 

/**
 * Created by yjl on 2020/7/27.
 * 工厂模式之抽象工厂模式
 * 工厂模式介绍地址:https://blog.csdn.net/qq_27471405/article/details/107607047
 * 微信公众号:zygxsq
 */
//给工厂类一个接口
public interface Provider {
	public Sender produce();
}

    //Implementation classes of two factories

//Mail service factory implementation class

/**
 * Created by yjl on 2020/7/27.
 * 工厂模式之抽象工厂模式
 * 工厂模式介绍地址:https://blog.csdn.net/qq_27471405/article/details/107607047
 * 微信公众号:zygxsq
 */
//邮件服务工厂实现类
public class SendMailFactory implements Provider {
	public Sender produce() {
		return new MailSender();
	}
}

//SMS factory implementation class

/**
 * Created by yjl on 2020/7/27.
 * 工厂模式之抽象工厂模式
 * 工厂模式介绍地址:https://blog.csdn.net/qq_27471405/article/details/107607047
 * 微信公众号:zygxsq
 */
//短信服务工厂实现类
public class SendSmsFactory implements Provider {
	public Sender produce() {
		return new SmsSender();
	}
}

 

    //Test class

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

operation result:


    Note: 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 at the same time make a factory class to implement the Provider interface, and it will be OK, without changing the existing ones. Code. Doing this has better scalability

 
 


Advanced use

In our actual web project use, the interface is called through the three-tier architecture dao, service, and controller.

When the Controller layer is called on the front end, how does the back end know which factory the front end wants to use?

This requires a front-end and back-end agreement to pass in a string, and each string represents the need to call a different factory class

After the front end passes the specified string in, our back end can be implemented in many ways

1. Judge by if...else...

demo

Other methods are the same as the abstract factory pattern, we just added FactoryaaaController

//Controller layer

/**
 * Created by yjl on 2020/7/27.
 * 工厂模式之高级使用
 * 工厂模式介绍地址:https://blog.csdn.net/qq_27471405/article/details/107607047
 * 微信公众号:zygxsq
 */
@RestController
@RequestMapping(value = "aaa",method = RequestMethod.GET)
public class FactoryaaaController {


	@ResponseBody
	@RequestMapping("/getFactory")
	public void getaaa(String projectName,String aaa,String bbb){
		//通过前端传递指定projectName来判断
		if("email".equals(projectName)){
			Provider provider = new SendMailFactory();
			Sender sender = provider.produce();
			sender.Send();

		}else if ("sms".equals(projectName)){
			Provider provider = new SendSmsFactory();
			Sender sender = provider.produce();
			sender.Send();

		}

	}

}

operation result:

 

This method will encounter similar problems before, that is, if another factory that sends MMS is added or other back-end engineers add another factory, then the code in the Controller will be changed. What we require is decoupling , Try to expand horizontally, do not move the code here, then you need to use the second method

2. Through annotations, aspect programming

demo:

 //ProjectName

package cn.zygxsq.design.config;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * Created by yjl on 2020/7/27.
 */
@Documented
@Retention(RUNTIME)
@Target({ElementType.TYPE})
public @interface ProjectName {
    String name() default "";
}

//SpringContextUtil 

/**
 * Created by yjl on 2020/7/27.
 */
@Component
public class SpringContextUtil implements ApplicationContextAware {
    private static Logger logger = LoggerFactory.getLogger(SpringContextUtil.class);

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (SpringContextUtil.applicationContext == null) {
            SpringContextUtil.applicationContext = applicationContext;
        }
        logger.info("初始化ApplicationContext:" + applicationContext);
    }

    /**
     * @return org.springframework.context.ApplicationContext
     * @description 获取applicationContext
     * @params []
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * @return java.lang.Object
     * @description 通过beanName获取Bean
     * @params [name]
     */
    public static Object getBean(String beanName) {
        return getApplicationContext().getBean(beanName);
    }

    /**
     * @return T
     * @description 通过class获取Bean
     * @params [clazz]
     */
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);
    }

    /**
     * @return T
     * @description 通过beanName和class返回指定的Bean
     * @params [name, clazz]
     */
    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }

    /**
     * @return Map<String, T>
     * @description 获取指定类型的所有bean实例
     * @params [clazz]
     */
    public static <T> Map<String, T> getBeansByType(Class<T> clazz) {
        Map<String, T> instances = getApplicationContext().getBeansOfType(clazz);
        return instances;
    }

    /**
     * @return T
     * @description 根据名称获取bean实例
     * @params [clazz, markCode]
     */
    public static <T> T getBeanByProjectName(Class<T> clazz, String projectName) throws Exception{
        Map<String, T> instances = getBeansByType(clazz);
        if (instances.isEmpty()) {
            logger.info("未获取到类型[" + clazz + "]Bean列表!");
            return null;
        }
//        logger.info("获取类型[" + clazz + "]Bean列表:" + instances);
        for (String beanName : instances.keySet()) {
            T instance = instances.get(beanName);
            ProjectName project = instance.getClass().getAnnotation(ProjectName.class);

            if (project.name().equals(projectName)) {
                return instance;
            }
        }

        logger.info("所有的Bean列表["+instances.toString()+"]不存在您要找的ProjectName(name=\""+projectName+"\")注解");
        throw new Exception("所有的Bean列表["+instances.toString()+"]不存在您要找的ProjectName(name=\""+projectName+"\")注解");

        //return null;
    }

}

//FactorybbbController

/**
 * Created by yjl on 2020/7/27.
 * 工厂模式之高级使用
 * 工厂模式介绍地址:https://blog.csdn.net/qq_27471405/article/details/107607047
 * 微信公众号:zygxsq
 */
@RestController
@RequestMapping(value = "bbb",method = RequestMethod.GET)
public class FactorybbbController {


	@ResponseBody
	@RequestMapping("/getFactorybbb")
	public void getbbb(String projectName,String aaa,String bbb){
		//通过前端传递指定projectName来判断
		try {
			if (projectName==null){
				projectName="sms";
			}
			Provider provider = SpringContextUtil.getBeanByProjectName(Provider.class, projectName);
			Sender produce = provider.produce();
			produce.Send();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}



}

Other methods are the same as the abstract factory pattern. At the same time, we need to add ProjectName annotations to all subclasses that implement the factory to indicate what factory this is

/**
 * Created by yjl on 2020/7/27.
 * 工厂模式之高级使用
 * 工厂模式介绍地址:https://blog.csdn.net/qq_27471405/article/details/107607047
 * 微信公众号:zygxsq
 */
//短信服务工厂实现类
@ProjectName(name = "sms")
@Component
public class SendSmsFactory implements Provider {
	public Sender produce() {
		return new SmsSender();
	}
}
/**
 * Created by yjl on 2020/7/27.
 * 工厂模式之高级使用
 * 工厂模式介绍地址:https://blog.csdn.net/qq_27471405/article/details/107607047
 * 微信公众号:zygxsq
 */
//邮件服务工厂实现类
@ProjectName(name = "mail")
@Component
public class SendMailFactory implements Provider {
	public Sender produce() {
		return new MailSender();
	}
}

 

operation result:

 The advantage of the above is that when this project has a lot of different back-end engineers to implement, you implement the mail and SMS services, and other engineers implement other services, then you only need to add your own annotation ProjectName in each subclass factory That's it, then let the front end pass in the specified projectname, so that you don't need to modify the Controller layer method to avoid conflicts and other problems, and you can achieve the same functional effect.

 

The relevant code of the factory mode has been put on github, you can download it to test and use:

https://github.com/jalenFish/design-patterns/tree/master/src/main/java/cn/zygxsq/design/module/factoryPattern

 


Reference article 

https://www.runoob.com/design-pattern/factory-pattern.html

Thanks to the original author for sharing, so that technical people can solve the problem faster 

 

Guess you like

Origin blog.csdn.net/qq_27471405/article/details/107607047