El diseño del generador de patrones en Java

E

 

Introducción

En este artículo, analizaremos Designer Builder Pattern y mostraremos su aplicación en Java.

Los patrones de diseño son solo conjuntos de prácticas estandarizadas comúnmente utilizadas en la industria del desarrollo de software. Representan soluciones, proporcionadas por el público, a problemas comunes encontrados en las tareas diarias de desarrollo de software.

Un buen diseñador no tiene que centrarse en objetos listos para usar porque conoce la abstracción, la herencia y el polimorfismo. Un experto en diseño crea diseños que son sostenibles y flexibles, pero lo más importante: comprensibles.

Una buena idea vinculada por el inventor no es una buena idea.

Patrones de diseño creacional

Los patrones de diseño creacional se centran en la creación de objetos. La creación de objetos es una parte muy importante del diseño orientado a objetos, y optimizar esta tarea en aplicaciones complejas y de alto rendimiento es extremadamente importante.

Estos patrones gobiernan la forma en que definimos y diseñamos las cosas, así como cómo las hacemos instantáneamente. Algunos incorporan la lógica de creación de los usuarios y manejan la creación (Factory y Abstract Factory), algunos se enfocan en el proceso de construcción de los objetos en sí (Builder), algunos minimizan el costo de creación (Prototype) y algunos controlan el número de casos en el JVM total (Singleton).

En este artículo, nos sumergiremos en el patrón de diseño del constructor.

El patrón de diseño del constructor

Definición

Design Pattern Builder construye una partición de objeto compleja a partir de su representación. Esto se hace anidando static una clase que asigna los valores requeridos antes de que se devuelva el caso.

Otra cosa a tener en cuenta es que el patrón de constructor se usa a menudo para crear objetos inmóviles. Hay poco daño en la configuración de métodos, y dado que no los usamos cuando tenemos el patrón de constructor en su lugar, es mucho más fácil hacer cosas inamovibles, sin pasar todos los parámetros en la llamada al constructor.

Motivación

Poner un objeto en Java es simple. Usamos el new palabra clave, seguida del constructor y los parámetros que estamos asignando al objeto. Puede aparecer instantáneamente:

Cookie chocolateChip = new Cookie("Chocolate Chip Cookie");

La cadena se pasa al constructor, y está claro sin ver la definición de clase que es el tipo / nombre de una cookie.

Sin embargo, si queremos inculcar instantáneamente una clase más compleja, como una red neuronal, en este estilo, nos estamos dirigiendo a:

SingleLayerNetwork configuration = new NeuralNetConfiguration(4256, STOCHASTIC_GRADIENT_DESCENT,
                                                              new Adam(), 1e-4, numRows*numColumns,
                                                              1000, RELU, XAVIER);

Incluso con solo 8 parámetros, el código se vuelve rápidamente ilegible e incomprensible. Incluso para el desarrollador que escribió la definición de clase en primer lugar. ¿Qué sucede cuando un nuevo desarrollador intenta usar esta clase?

O mejor aún, imagina que tienes que llamar al constructor de esta clase para instalarlo instantáneamente:

public class SmartHome {
    private String name;
    private int serialNumber;
    private String addressName;
    private String addressNumber;
    private String city;
    private String country;
    private String postalCode;
    private int light1PortNum;
    private int light2PortNum;
    private int door1PortNum;
    private int door2PortNum;
    private int microwavePortNum;
    private int tvPortNum;
    private int waterHeaterPortNum;

    public SmartHome(String name, int serialNumber, String addressName, String addressNumber, String city, String country, String postalCode, int light1PortNum, int light2PortNum, int door1PortNum, int door2PortNum, int microwavePortNum, int tvPortNum, int waterHeaterPortNum) {
        // Assigning values in the constructor call
    }

    // Getters and Setters
}

Hay demasiados argumentos de constructor frente a nosotros, y sin mucho tipo, estaremos viendo una gran llamada de constructor sin forma de saber qué es.

Tenga en cuenta también que dos constructores con el mismo tipo de parámetro, pero con diferentes nombres de variable, no se aceptan en Java.

Los siguientes dos constructores no están permitidos en Java porque el compilador no puede separarlos:

public SmartHome(int door1PortNum) { ... }
public SmartHome(int door2PortNum) { ... }

Incluso si tenemos un constructor con un tipo de parámetro int:

public SmartHome(int portNum) { ... }

Sabemos que necesitamos establecer un número de puerto, pero no sabremos si ese número es el puerto de la puerta, luz, microondas, TV o calentador de agua.

Esta clase pronto no se podrá utilizar en un entorno de equipo. Incluso si eres un programa individual, tienes la suerte de recordar el orden de los parámetros después de una semana sin tomar la clase al instante.

SEO aquí es donde salta el generador de patrones:

El patrón de constructor separa la construcción de la representación.

¿Qué significa esto?

La construcción se realiza en la propia clase. Es la representación que vemos como usuario de la clase. En este momento, las dos clases anteriores están vinculadas a estas dos clases; simplemente llamamos al constructor para pasar los argumentos.

Al separar estas dos cosas, podemos hacer que la representación de clases sea más simple, más agradable y más legible, y el constructor hace su parte.

Implementación

Hay una serie de pasos a seguir para implementar Builder Pattern. Continuando con nuestros ejemplos anteriores, usaremos el SmartHome clase para mostrar los pasos:

  • A. static una clase de constructores debe estar integrada en nuestra SmartHome sonó
  • El es SmartHome debería haber un constructor private para que el usuario final no pueda llamarlo
  • La clase de constructor debe tener un nombre intuitivo, como SmartHomeBuilder
  • El es SmartHomeBuilder la clase tendrá las mismas áreas que el SmartHome sonó
  • Los parques en el SmartHome una clase puede ser final o no, dependiendo de si quieres que sea inamovible o no
  • El es SmartHomeBuilder Habrá métodos en la clase que establecen los valores, similares a los métodos de configuración. Estos métodos serán una característica del SmartHomeBuilder como tipo de retorno, asigne los valores pasados ​​a los campos de clase del constructor estático y siga la convención de nomenclatura del constructor. Por lo general comienzan with, in, atetc. en vez de set.
  • UN build() método de inyectar estos valores en SmartHome y devuelve un ejemplo de ello.

Dicho esto, apliquemos el patrón de constructor en nuestra clase de muestra:

public class SmartHome {
    // Fields omitted for brevity
    // The same fields should be in `SmartHome` and `SmartHomeBuilder`

    // Private constructor means we can't instantiate it
    // by simply calling `new SmartHome()`
    private SmartHome() {}

    public static class SmartHomeBuilder {
        private String name;
        private int serialNumber;
        private String addressName;
        private String addressNumber;
        private String city;
        private String country;
        private String postalCode;
        private int light1PortNum;
        private int light2PortNum;
        private int door1PortNum;
        private int door2PortNum;
        private int microwavePortNum;
        private int tvPortNum;
        private int waterHeaterPortNum;

        public SmartHomeBuilder withName(String name) {
            this.name = name;
            return this;
        }

        public SmartHomeBuilder withSerialNumber(int serialNumber) {
            this.serialNumber = serialNumber;
            return this;
        }

        public SmartHomeBuilder withAddressName(String addressName) {
            this.addressName = addressName;
            return this;
        }

        public SmartHomeBuilder inCity(String city) {
            this.city = city;
            return this;
        }

        public SmartHomeBuilder inCountry(String country) {
            this.country = country;
            return this;
        }

        // The rest of the methods are omitted for brevity
        // All follow the same principle

        public SmartHome build() {
            SmartHome smartHome = new SmartHome();
            smartHome.name = this.name;
            smartHome.serialNumber = this.serialNumber;
            smartHome.addressName = this.addressName;
            smartHome.city = this.city;
            smartHome.country = this.country;
            smartHome.postalCode = this.postalCode;
            smartHome.light1PortNum = this.light1PortNum;
            smartHome.light2PortNum = this.light2PortNum;
            smartHome.door1PortNum = this.door1PortNum;
            smartHome.door2PortNum = this.door2PortNum;
            smartHome.microwavePortNum = this.microwavePortNum;
            smartHome.tvPortNum = this.tvPortNum;
            smartHome.waterHeaterPortNum = this.waterHeaterPortNum;

            return smartHome;
        }
    }
}

El es SmartHome la clase no tiene constructores públicos y la única forma de SmartHome hay un objeto a través del SmartHomeBuilder clase, así:

SmartHome smartHomeSystem = new SmartHome
    .SmartHomeBuilder()
    .withName("RaspberrySmartHomeSystem")
    .withSerialNumber(3627)
    .withAddressName("Main Street")
    .withAddressNumber("14a")
    .inCity("Kumanovo")
    .inCountry("Macedonia")
    .withPostalCode("1300")
    .withDoor1PortNum(342)
    .withDoor2PortNum(343)
    .withLight1PortNum(211)
    .withLight2PortNum(212)
    .withMicrowavePortNum(11)
    .withTvPortNum(12)
    .withWaterHeaterPortNum(13)
    .build();

System.out.println(smartHomeSystem);

Si bien hemos hecho que la clase en sí sea más compleja al incluir una clase anidada con campos duplicados, la representación está separada de la creación.

Claramente lo que estamos construyendo y colocando instantáneamente el objeto. Es legible, comprensible y cualquiera puede usar tus clases para construir cosas.

Volviendo al ejemplo de la red neuronal del mundo real, se vería un poco así:

MultiLayerNetwork conf = new NeuralNetConfiguration.Builder()
    .seed(rngSeed)
    .optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT)
    .updater(new Adam())
    .l2(1e-4)
    .list()
    .layer(new DenseLayer.Builder()
        .nIn(numRows * numColumns) // Number of input datapoints.
        .nOut(1000) // Number of output datapoints.
        .activation(Activation.RELU) // Activation function.
        .weightInit(WeightInit.XAVIER) // Weight initialization.
        .build())
    .layer(new OutputLayer.Builder(LossFunctions.LossFunction.NEGATIVELOGLIKELIHOOD)
        .nIn(1000)
        .nOut(outputNum)
        .activation(Activation.SOFTMAX)
        .weightInit(WeightInit.XAVIER)
        .build())
    .pretrain(false).backprop(true)
    .build()

Código de crédito: DeepLearning4j – Inicio rápido

Ventajas y desventajas

Aparte del punto más obvio sobre el uso de Builder Pattern, hay algunas otras ventajas que pueden no ser muy obvias a primera vista:

  • Puede cambiar la implementación del objeto de la forma que desee y simplemente actualizar los métodos. La interfaz abstracta está frente al usuario final a través de la clase de construcción estática y no pertenece a la implementación básica.
  • Apoya la inclusión desacoplando la expresión del objeto de la construcción.

El único inconveniente real es que aumenta la cantidad de código en los modelos de dominio. Suelen ser largas ya, aunque relativamente sencillas (lanzamientos, puertas y quilters). Sin embargo, rara vez solicitaría estas clases de todos modos.

En general, las ventajas superan a las desventajas del Pattern Builder, por lo que se usa ampliamente en muchas aplicaciones complejas, marcos y bibliotecas, en particular.

Conclusión

Los patrones de diseño son solo conjuntos de prácticas estandarizadas que se utilizan en la industria del desarrollo de software. Representan soluciones, proporcionadas por el público, a problemas comunes encontrados en las tareas diarias de desarrollo de software.

En este artículo, profundizamos en un patrón de diseño creativo central que se encarga de la construcción de objetos y permite a los desarrolladores construir objetos complejos con menos errores de inspiración humana y mejora la sostenibilidad y la escalabilidad.

El patrón de diseño de constructores ofrece varias ventajas sobre tomar clases instantáneamente a través de constructores, con una desventaja que realmente no se compara con la cantidad de beneficios que puede obtener al contratarlo.

.

About the author

Ramiro de la Vega

Bienvenido a Pharos.sh

Soy Ramiro de la Vega, Estadounidense con raíces Españolas. Empecé a programar hace casi 20 años cuando era muy jovencito.

Espero que en mi web encuentres la inspiración y ayuda que necesitas para adentrarte en el fantástico mundo de la programación y conseguir tus objetivos por difíciles que sean.

Add comment

Sobre mi

Últimos Post

Etiquetas

Esta web utiliza cookies propias para su correcto funcionamiento. Al hacer clic en el botón Aceptar, aceptas el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad