El dise帽o del generador de patrones en Java

     

    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 鈥嬧媋 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.

    .

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *