Patrones de diseño - Patrones de prototipo

1 Definición

El patrón de prototipo es usar una instancia de clase para especificar el tipo de objeto que se creará y crear nuevos objetos copiando estos prototipos. El patrón prototipo requiere que un objeto implemente una interfaz que pueda "clonarse" a sí mismo, de modo que se pueda crear una nueva instancia copiando un objeto de instancia en sí mismo.

diagrama de 2 clases

 Clase prototipo abstracta (Prototype): Es la interfaz que declara el método clon y es la clase padre común de todas las clases prototipo concretas, puede ser una interfaz, una clase abstracta o incluso una clase de implementación concreta.

Clase de prototipo concreto (ConcretePrototype): implementa el método de clonación declarado en la clase de prototipo abstracto y devuelve un objeto de clonación propio en el método de clonación.

Clase de cliente (Cliente): en la clase de cliente, para usar el objeto prototipo, solo necesita crear o directamente NUEVO (instanciar un) objeto prototipo a través del método de fábrica, y luego puede obtener múltiples objetos idénticos a través del método de clonación del objeto prototipo. Dado que el cliente está programado para objetos prototipo abstractos, ¡también se puede reemplazar fácilmente con diferentes tipos de objetos prototipo!

3 pros y contras del modo prototipo

Como una forma de crear rápidamente una gran cantidad de objetos idénticos o similares, el modo prototipo se usa ampliamente en el desarrollo de software. ¡Las operaciones CTRL+C y CTRL+V proporcionadas por muchos software son aplicaciones típicas del modo prototipo!

3.1 Ventajas

Cuando la instancia del objeto creado es más compleja, ¡usar el patrón prototipo puede simplificar el proceso de creación del objeto!

Buena extensibilidad, porque la clase prototipo abstracta se usa al escribir el modo prototipo, la clase prototipo específica se puede leer a través de la configuración cuando el cliente está programando.

Puede usar la copia profunda para guardar el estado de un objeto y usar el modo prototipo para copiar. Simplemente pase a cuando necesite recuperarse hasta cierto punto. Por ejemplo, nuestra especie de idea tiene versiones históricas, y git también tiene tales operaciones. perfectamente trabajado!

3.2 Desventajas

Cada clase debe estar equipada con un método de copia, y el método de copia se encuentra en una clase. Cuando se modifica la clase existente, el código fuente debe modificarse, lo que viola el principio abierto-cerrado.

Al implementar la copia profunda, es necesario escribir código más complejo, y cuando hay múltiples referencias anidadas entre objetos, para implementar la copia profunda, las clases correspondientes a cada capa de objetos deben admitir la copia profunda, que es relativamente difícil de implementar. .

4 Copia superficial y copia profunda

Copia superficial La copia profunda es el concepto de copia para tipos de referencia. Cuando se usa una instancia de clase para llamar al método de clonación para generar un nuevo objeto, el tipo de valor (ocho tipos básicos, byte, corto, int, largo, char, doble, flotante, booleano) se copia directamente. el nuevo objeto cambia, el viejo El objeto no cambia con él.

Para el tipo de objeto de referencia, si es una copia superficial, la nueva instancia de clase y la instancia de clase original son las mismas para el tipo de objeto de referencia, es decir, si se cambia el valor del tipo de referencia del nuevo objeto, el valor del tipo de referencia del objeto antiguo también cambiará. Una copia profunda es una copia completamente separada del objeto al que se hace referencia, y ya no apunta a los objetos a los que se hace referencia original. Los cambios en el objeto al que se hace referencia por parte de la nueva instancia no afectarán a la instancia de la clase anterior.

El tipo String no es un tipo básico, es un tipo de referencia, pero el tipo String es un tipo inmutable. El valor al que apunta es constante. Cambiar su valor por el objeto clonado en realidad cambia el puntero del miembro de tipo String del objeto clonado. , que no afectará el valor del objeto clonado y su puntero.

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
}

Por ejemplo, ahora hay dos clases, Profesor y Alumno, y se hace referencia a la clase Alumno en la clase Profesor.

@Data
public class Teacher{
    private int number;

    private String name;

    private Student student;
}
@Data
public class Student{

    private String name;
}
public class client{


    Student stu = new Student("zhangsan");
    Teacher t = new Teacher(1, "lisi", stu);

}

La siguiente figura muestra la diferencia entre tipos de valor y tipos de referencia en copias superficiales y profundas.

5 método de clonación de Java

La clase Object de Java tiene un método de clonación, que está protegido y debe anularse para anular el método de clonación. Todas las clases en Java heredan la clase Object de forma predeterminada, por lo que todas las clases pueden implementar el método de clonación.

 protected native Object clone() throws CloneNotSupportedException;

El método clone() de Java hace una copia del objeto y se la devuelve a la persona que llama. En general, el método clone() satisface:
1. Para cualquier objeto x, existe x.clone() !=x//El objeto clonado no es el mismo objeto que el objeto original
2. Para cualquier objeto x, existe x .clone().getClass()= =x.getClass(), es decir, el objeto clonado es del mismo tipo que el objeto original
3. Si el método equals() del objeto x está correctamente definido, entonces x .clone().equals(x) debe establecerse.

Implementar el método clon es solo uno de ellos. También debe heredar la interfaz Cloneable, de lo contrario, se lanzará una CloneNotSupportedException.

package java.lang;

/**
 * A class implements the <code>Cloneable</code> interface to
 * indicate to the {@link java.lang.Object#clone()} method that it
 * is legal for that method to make a
 * field-for-field copy of instances of that class.
 * <p>
 * Invoking Object's clone method on an instance that does not implement the
 * <code>Cloneable</code> interface results in the exception
 * <code>CloneNotSupportedException</code> being thrown.
 * <p>
 * By convention, classes that implement this interface should override
 * <tt>Object.clone</tt> (which is protected) with a public method.
 * See {@link java.lang.Object#clone()} for details on overriding this
 * method.
 * <p>
 * Note that this interface does <i>not</i> contain the <tt>clone</tt> method.
 * Therefore, it is not possible to clone an object merely by virtue of the
 * fact that it implements this interface.  Even if the clone method is invoked
 * reflectively, there is no guarantee that it will succeed.
 *
 * @author  unascribed
 * @see     java.lang.CloneNotSupportedException
 * @see     java.lang.Object#clone()
 * @since   JDK1.0
 */
public interface Cloneable {
}

Los métodos básicos de clonación de objetos en Java son los siguientes:
1. Para obtener una copia del objeto, podemos utilizar el método clone() de la clase Object.
2. Anular el método clone() de la clase base en la clase derivada y declararlo como público.
3. En el método clone() de la clase derivada, llame a super.clone().
4. Implemente la interfaz Clonable en la clase derivada.

6 ejemplos de código

Rey Mono, hay 72 cambios, cuando Sun Wukong cambia del prototipo a otra forma, es equivalente a una copia de sí mismo, lo que se refiere al tipo de aro dorado.

6.1 Prototipo de Sun Wukong SunWuKong

@Data
public class SunWuKong implements Cloneable{

    /**
     * 表示孙悟空几号
     */
    private int number;

    /**
     * 孙悟空技能描述
     */
    private String desc;

    /**
     * 兵器尺寸
     */
    private Staff staff;
    /**
     * 浅复制
     * @return 孙悟空
     * @throws CloneNotSupportedException 不支持复制异常
     */
    @Override
    public Object clone() throws CloneNotSupportedException {
        SunWuKong sunWuKong = (SunWuKong)super.clone();
        return sunWuKong;
    }
}

6.2 Bastón de aro dorado

@Data
@AllArgsConstructor
public class Staff implements Cloneable{

    /**
     * 金箍棒的尺寸
     */
    private int size;
}

 6.3 Función principal MainClass

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-15 09:48
 **/
public class MainClass {

    public static void main(String[] args) {
        try {
            Staff staff = new Staff(200);
            SunWuKong sunWuKong1 = new SunWuKong();
            sunWuKong1.setNumber(1);
            sunWuKong1.setDesc("我是1号");
            sunWuKong1.setStaff(staff);
            System.out.println(sunWuKong1);
            System.out.println("*****************浅拷贝*******************");
            SunWuKong sunWuKong2 = (SunWuKong) sunWuKong1.clone();
            System.out.println(sunWuKong2);

            System.out.println("*****************改变属性*******************");
            staff.setSize(300);
            sunWuKong2.setNumber(2);
            sunWuKong2.setDesc("我原来是1号,我现在变了");
            System.out.println(sunWuKong1);
            System.out.println(sunWuKong2);
        }catch (CloneNotSupportedException e){
            System.out.println("对象不能被克隆");
        }
    }
}

6.4 Resultados de ejecución

6.5 Análisis de resultados

 Preste atención al objeto de referencia Staff. Cuando cambiamos el atributo del personal, el prototipo y el tipo de copia de Sun Wukong han cambiado, lo que significa que es una copia superficial.

7 Copia profunda utilizando la serialización de Java

7.1 Código prototipo

El código principal sigue siendo el mismo, solo es necesario agregar la interfaz Serializable heredada a la clase Staff y la clase SunWuKong, y agregar el método deepClone a SunWuKong.

@Data
public class SunWuKong implements Cloneable, Serializable{

    /**
     * 表示孙悟空几号
     */
    private int number;

    /**
     * 孙悟空技能描述
     */
    private String desc;

    /**
     * 兵器尺寸
     */
    private Staff staff;
    /**
     * 浅复制
     * @return 孙悟空
     * @throws CloneNotSupportedException 不支持复制异常
     */
    @Override
    public Object clone() throws CloneNotSupportedException {
        SunWuKong sunWuKong = (SunWuKong)super.clone();
        return sunWuKong;
    }

    public Object deepClone()throws IOException, ClassNotFoundException{
        //将对象写到流里
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);
        //从流里读回来
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return ois.readObject();
    }
}
@Data
@AllArgsConstructor
public class Staff implements Cloneable, Serializable {

    /**
     * 金箍棒的尺寸
     */
    private int size;
    
}

7.2 Código de función principal

public class MainClass {

    public static void main(String[] args) {
        try {
            Staff staff = new Staff(200);
            SunWuKong sunWuKong1 = new SunWuKong();
            sunWuKong1.setNumber(1);
            sunWuKong1.setDesc("我是1号");
            sunWuKong1.setStaff(staff);
            System.out.println(sunWuKong1);
            System.out.println("*****************浅拷贝*******************");
            SunWuKong sunWuKong2 = (SunWuKong) sunWuKong1.clone();

            staff.setSize(300);
            sunWuKong2.setNumber(2);
            sunWuKong2.setDesc("我原来是1号,我现在变2号");
            System.out.println(sunWuKong1);
            System.out.println(sunWuKong2);


            System.out.println("*****************深拷贝*******************");
            SunWuKong sunWuKong3 = (SunWuKong) sunWuKong1.deepClone();
            staff.setSize(400);
            sunWuKong3.setNumber(3);
            sunWuKong3.setDesc("我是深拷贝3号");
            System.out.println(sunWuKong1);
            System.out.println(sunWuKong2);
            System.out.println(sunWuKong3);
        }catch (CloneNotSupportedException e){
            System.out.println("对象不能被克隆");
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

7.3 Resultados de ejecución

 

7.4 Análisis de resultados 

Después de cambiar el atributo de tamaño del personal, los atributos de No. 1 y No. 2 se cambian, y No. 3 sigue siendo el atributo 300 antes de la clonación, lo que significa que la referencia al objeto se ha copiado nuevamente. 

8 citas

1. "Patrones de diseño Dahua"

2. Patrón de prototipo JAVA

3. Prototipo de patrón en java

4. Explica en detalle el método de clonación en Java

9 código fuente

https://github.com/airhonor/design-pattern-learning/tree/main/src/com/hz/design/pattern/prototype

Supongo que te gusta

Origin blog.csdn.net/honor_zhang/article/details/120412303
Recomendado
Clasificación