Enstringmiento de métodos: en java, el enstringmiento de métodos se usa para invocar múltiples métodos en el mismo objeto que ocurre como una sola declaración. El enstringmiento de métodos se implementa mediante una serie de métodos que devuelven la referencia this para una instancia de clase.
Implementación: como los valores devueltos de los métodos en una string son esta referencia, esta implementación nos permite invocar métodos en string al tener la siguiente invocación del método en el valor devuelto del método anterior en la string.
// Java code to demonstrate method chaining final class Student { // instance fields private int id; private String name; private String address; // Setter Methods // Note that all setters method // return this reference public Student setId(int id) { this.id = id; return this; } public Student setName(String name) { this.name = name; return this; } public Student setAddress(String address) { this.address = address; return this; } @Override public String toString() { return "id = " + this.id + ", name = " + this.name + ", address = " + this.address; } } // Driver class public class MethodChainingDemo { public static void main(String args[]) { Student student1 = new Student(); Student student2 = new Student(); student1.setId(1).setName("Ram").setAddress("Noida"); student2.setId(2).setName("Shyam").setAddress("Delhi"); System.out.println(student1); System.out.println(student2); } }
Producción:
id = 1, name = Ram, address = Noida id = 2, name = Shyam, address = Delhi
Necesidad de patrón de generador: el enstringmiento de métodos es un patrón de diseño útil pero, sin embargo, si se accede al mismo tiempo , un subproceso puede observar que algunos campos contienen valores inconsistentes. Aunque todos los métodos de establecimiento en el ejemplo anterior son atómicos , las llamadas en el enstringmiento de métodos pueden conducir a un estado de objeto inconsistente cuando el objeto se modifica simultáneamente. El siguiente ejemplo puede llevarnos a una instancia de Estudiante en un estado inconsistente , por ejemplo, un estudiante con nombre Ram y dirección Delhi .
// Java code to demonstrate need of Builder Pattern // Server Side Code final class Student { // instance fields private int id; private String name; private String address; // Setter Methods // Note that all setters method // return this reference public Student setId(int id) { this.id = id; return this; } public Student setName(String name) { this.name = name; return this; } public Student setAddress(String address) { this.address = address; return this; } @Override public String toString() { return "id = " + this.id + ", name = " + this.name + ", address = " + this.address; } } // Client Side Code class StudentReceiver { private final Student student = new Student(); public StudentReceiver() { Thread t1 = new Thread(new Runnable() { @Override public void run() { student.setId(1).setName("Ram").setAddress("Noida"); } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { student.setId(2).setName("Shyam").setAddress("Delhi"); } }); t1.start(); t2.start(); } public Student getStudent() { return student; } } // Driver class public class BuilderNeedDemo { public static void main(String args[]) { StudentReceiver sr = new StudentReceiver(); System.out.println(sr.getStudent()); } }
La salida puede ser:
id = 2, name = Shyam, address = Noida
Otra salida inconsistente puede ser
id = 0, name = null, address = null
Nota: intente ejecutar las declaraciones del método principal en bucle (es decir, varias requests al servidor simultáneamente).
Para resolver este problema, existe un patrón Builder para garantizar la seguridad de subprocesos y la atomicidad de la creación de objetos.
Implementación: en el patrón Builder, tenemos una clase estática interna llamada Builder dentro de nuestra clase Server con campos de instancia para esa clase y también tenemos un método de fábrica para devolver una nueva instancia de la clase Builder en cada invocación. Los métodos setter ahora devolverán la referencia de la clase Builder . También tendremos un método de compilación para devolver instancias de la clase del lado del servidor, es decir, la clase externa.
// Java code to demonstrate Builder Pattern // Server Side Code final class Student { // final instance fields private final int id; private final String name; private final String address; public Student(Builder builder) { this.id = builder.id; this.name = builder.name; this.address = builder.address; } // Static class Builder public static class Builder { /// instance fields private int id; private String name; private String address; public static Builder newInstance() { return new Builder(); } private Builder() {} // Setter methods public Builder setId(int id) { this.id = id; return this; } public Builder setName(String name) { this.name = name; return this; } public Builder setAddress(String address) { this.address = address; return this; } // build method to deal with outer class // to return outer instance public Student build() { return new Student(this); } } @Override public String toString() { return "id = " + this.id + ", name = " + this.name + ", address = " + this.address; } } // Client Side Code class StudentReceiver { // volatile student instance to ensure visibility // of shared reference to immutable objects private volatile Student student; public StudentReceiver() { Thread t1 = new Thread(new Runnable() { @Override public void run() { student = Student.Builder.newInstance() .setId(1) .setName("Ram") .setAddress("Noida") .build(); } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { student = Student.Builder.newInstance() .setId(2) .setName("Shyam") .setAddress("Delhi") .build(); } }); t1.start(); t2.start(); } public Student getStudent() { return student; } } // Driver class public class BuilderDemo { public static void main(String args[]) { StudentReceiver sr = new StudentReceiver(); System.out.println(sr.getStudent()); } }
Se garantiza que la salida será una de las siguientes:
id = 1, name = Ram, address = Noida
O
id = 2, name = Shyam, address = Delhi
El método de fábrica Builder.newInstance() también se puede llamar con los argumentos necesarios para obtener una instancia de Builder sobrecargándola. El objeto de la clase Student se construye con la invocación del método build() .
La implementación anterior del patrón Builder hace que la clase Student sea inmutable y, en consecuencia , segura para subprocesos .
También tenga en cuenta que el campo de estudiante en el código del lado del cliente no se puede declarar final porque se le asigna un nuevo objeto inmutable. Pero debe declararse volátil para garantizar la visibilidad de la referencia compartida a objetos inmutables. También los miembros privados de la clase Builder mantienen la encapsulación.
Eche un vistazo al método de adición de la clase StringBuilder en el paquete java.lang para comprender mejor las implementaciones del patrón Builder.
Publicación traducida automáticamente
Artículo escrito por gaurav miglani y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA