Uso del patrón de fábrica en el patrón de diseño java | uso de patrón de fábrica ordinario, patrón de método de fábrica múltiple, patrón de método de fábrica estático, patrón de fábrica abstracto | uso avanzado del patrón de fábrica

Tabla de contenido

Patrón de método de fábrica (patrón de fábrica)

Prefacio

1. Modelo de fábrica ordinario

 manifestación:

resultado de la operación: 

    2. Múltiples patrones de métodos de fábrica

manifestación:

 resultado de la operación:

    3. Patrón de método de fábrica estático

manifestación:

  resultado de la operación:

 4. Modo de fábrica abstracta (Fábrica abstracta)

manifestación:

resultado de la operación:

Uso avanzado

1. Juzga por si ... si no ...

manifestación

resultado de la operación:

2. Mediante anotaciones, programación de aspectos

manifestación:

resultado de la operación:


 

Patrón de método de fábrica (patrón de fábrica)

Prefacio

Hay tres patrones de métodos de fábrica: patrón de fábrica ordinario, patrones de métodos de fábrica múltiples, patrones de métodos de fábrica estáticos

En el modo de fábrica, no exponemos la lógica de creación al cliente al crear un objeto, y usamos una interfaz común para apuntar al objeto recién creado.

Ventajas:  1. Una persona que llama quiere crear un objeto, siempre que sepa su nombre. 2. Alta escalabilidad: si desea agregar un producto, simplemente amplíe una clase de fábrica. 3. Proteja la implementación específica del producto, la persona que llama solo se preocupa por la interfaz del producto.

Desventajas: cada vez que se agrega un producto, se debe agregar una clase concreta y una fábrica de implementación de objetos, lo que duplica el número de clases en el sistema, lo que aumenta la complejidad del sistema hasta cierto punto y al mismo tiempo aumenta la clase específica del sistema. confiar. Esto no es bueno.

Escenarios de uso:  1. Grabador de registros: los registros pueden grabarse en discos duros locales, eventos del sistema, servidores remotos, etc. El usuario puede elegir dónde grabar los registros. 2. Acceso a la base de datos, cuando el usuario no sabe qué tipo de base de datos utiliza el sistema al final, y la base de datos puede cambiar. 3. Para diseñar un marco para conectarse al servidor, se requieren tres protocolos, "POP3", "IMAP" y "HTTP", que se pueden utilizar como clases de productos para implementar una interfaz juntos.

Nota: Como patrón de clase de creación, el patrón de método de fábrica se puede utilizar siempre que sea necesario generar objetos complejos. Una cosa a tener en cuenta es que los objetos complejos son adecuados para usar el patrón de fábrica, mientras que los objetos simples, especialmente los objetos que solo necesitan ser creados a través de nuevos, no necesitan usar el patrón de fábrica. Si usa el patrón de fábrica, debe introducir una clase de fábrica, lo que aumentará la complejidad del sistema.

    


1. Modelo de fábrica ordinario

Consiste en establecer una clase de fábrica para crear instancias de clases de productos que implementen la misma interfaz.  

 manifestación:

// La interfaz para enviar SMS y correo electrónico

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


// La clase de implementación del envío de correo

/**
 * 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("发送邮件!");
	}
}


  
// Clase de implementación para enviar 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("发送短信!");
	}
}

 

 // Crea una clase de fábrica

/**
 * 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;
		}
	}
}


   // Clase de prueba

/**
 * 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();
	}
}

resultado de la operación: 

 


    2. Múltiples patrones de métodos de fábrica

Es una mejora del patrón de método de fábrica ordinario. En el patrón de método de fábrica ordinario, si la cadena pasada es incorrecta, el objeto no se puede crear correctamente y el patrón de método de fábrica múltiple proporciona varios métodos de fábrica para crear objetos por separado.

    // Modifica el código anterior y cambia la clase SendFactory .// No
    es necesario crear un objeto basado en la clase de cadena pasada por el usuario.

manifestación:


  

// Crea una clase de fábrica

/**
 * 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();
	}
}

// Clase de prueba 

 

/**
 * 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();
	}
}

 resultado de la operación:


 

    3. Patrón de método de fábrica estático

Establezca los métodos en los múltiples patrones de métodos de fábrica anteriores como estáticos, sin crear una instancia, simplemente llámelo directamente.

manifestación:

 // Crea una clase de fábrica

/**
 * 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();
	}
}


  // Clase de prueba

/**
 * 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();
	}
}

  resultado de la operación:

 



 4. Modo Abstract Factory (Abstract Factory)

Un problema con el patrón del método de fábrica es que la creación de una clase depende de la clase de fábrica. En otras palabras, si desea expandir el programa, debe modificar la clase de fábrica. Esto viola el principio de cierre. Por lo tanto, desde una perspectiva de diseño, existen ciertos problemas. ,¿Cómo resolver? El patrón de fábrica abstracto se usa para crear múltiples clases de fábrica, de modo que una vez que se deben agregar nuevas funciones, se puede agregar una nueva clase de fábrica directamente sin modificar el código anterior. 

manifestación:

   

Desmonte la clase de fábrica de creación anterior y use subclases de la clase abstracta para crear diferentes clases de fábrica

// Crea una interfaz para la clase de fábrica 

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

    // Clases de implementación de dos fábricas

// Clase de implementación de la fábrica de servicios de correo

/**
 * 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();
	}
}

// Clase de implementación de fábrica de SMS

/**
 * 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();
	}
}

 

    // Clase de prueba

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

resultado de la operación:


    Nota: La ventaja de este modo es que si deseas agregar una función: enviar información oportuna, solo necesitas hacer una clase de implementación para implementar la interfaz de Remitente, y al mismo tiempo hacer una clase de fábrica para implementar la interfaz de Proveedor, y estará bien, sin cambiar las existentes. Código. Hacer esto tiene una mejor escalabilidad

 
 


Uso avanzado

En nuestro uso real de proyectos web, las llamadas a la interfaz se realizan a través del dao, el servicio y el controlador de la arquitectura de tres niveles.

Cuando se llama a la capa de controlador en el front-end, ¿cómo sabe el back-end qué fábrica quiere usar el front-end?

Esto requiere un acuerdo de front-end y back-end para pasar una cadena, y cada cadena representa la necesidad de llamar a una clase de fábrica diferente

Después de que el front-end pasa la cadena especificada, nuestro back-end se puede implementar de muchas maneras

1. Juzga por si ... si no ...

manifestación

Otros métodos son los mismos que los del patrón de fábrica abstracto, acabamos de agregar FactoryaaaController

// Capa de controlador

/**
 * 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();

		}

	}

}

resultado de la operación:

 

Este método encontrará problemas similares antes, es decir, si se agrega otra fábrica que envía MMS o si otros ingenieros de back-end agregan otra fábrica, entonces se cambiará el código en el Controlador. Lo que necesitamos es desacoplar , Intente expandir horizontalmente, no mueva el código aquí, entonces debe usar el segundo método

2. Mediante anotaciones, programación de aspectos

manifestación:

 //Nombre del proyecto

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();
		}

	}



}

Otros métodos son los mismos que los del patrón de fábrica abstracta. Al mismo tiempo, necesitamos agregar anotaciones ProjectName a todas las subclases que implementan la fábrica para indicar qué fábrica es.

/**
 * 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();
	}
}

 

resultado de la operación:

 La ventaja de lo anterior es que cuando este proyecto tiene muchos ingenieros de back-end diferentes para implementar, usted implementa los servicios de correo y SMS, y otros ingenieros implementan otros servicios, entonces solo necesita agregar su propia anotación ProjectName en cada fábrica de subclase Eso es todo, luego deje que el front-end pase en el nombre del proyecto especificado, para que no necesite modificar el método de la capa del controlador para evitar conflictos y otros problemas, y pueda lograr el mismo efecto funcional.

 

El código relevante del modo de fábrica se ha puesto en github, puede descargarlo para probarlo y usarlo:

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

 


Articulo de referencia 

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

Gracias al autor original por compartir, para que los técnicos puedan resolver el problema más rápido 

 

Supongo que te gusta

Origin blog.csdn.net/qq_27471405/article/details/107607047
Recomendado
Clasificación