Modo de prototipo de patrones de diseño comunes

concepto

El patrón de prototipo (patrón de prototipo) se refiere a que la instancia de prototipo especifica los tipos de objetos que se crearán y crea nuevos objetos copiando estos prototipos. Pertenece al patrón de creador. El
patrón de prototipo incluye principalmente tres roles:

  • Cliente : la clase de cliente proporciona una solicitud para crear un objeto
  • Prototipo abstracto (prototipo) : especifique la interfaz de copia
  • Prototipo de hormigón : el objeto a copiar

Nota: El modo de crear un objeto a través de la copia del objeto en lugar de la nueva palabra clave se llama modo prototipo

lograr

Clon superficial

Escritura estándar

1. Cree una interfaz prototipo

public interface IPrototype<T> {
    
    
    T clone();
}

2. Crea un prototipo de hormigón

public class ConcretePrototype implements IPrototype {
    
    
    int age;
    String name;

    @Override
    public String toString() {
    
    
        return "ConcretePrototype{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    @Override
    public ConcretePrototype clone() {
    
    
        ConcretePrototype cp=new ConcretePrototype();
        cp.setAge(this.age);
        cp.setName(this.name);
        return cp;
    }
}

3. Prueba

public class PrototypeTest {
    
    
    public static void main(String[] args) {
    
    
        //创建原型
        ConcretePrototype cp =new ConcretePrototype();
        cp.setName("tom");
        cp.setAge(21);
        System.out.println(cp);
        //拷贝原型
        ConcretePrototype cloneType=cp.clone();
        System.out.println(cloneType);
    }
}

Resultado de la operación: En
Inserte la descripción de la imagen aquí
este momento, alguien preguntó, ¿no es esto solo copiar los atributos en el objeto? No es muy diferente del original. De hecho, el proceso de asignación anterior lo hacemos nosotros mismos. En la codificación real, generalmente no desperdiciamos este tipo de trabajo físico.
A continuación, analizamos otra forma de escribir el modo prototipo.

Implementar la interfaz clonable en JDK

JDK nos ha ayudado a implementar una API de subprocesos, solo necesitamos implementar la interfaz de interfaz clonable.

1. Crea un prototipo de hormigón

public class ConcretePrototype implements Cloneable {
    
    
    int age;
    String name;

    @Override
    public String toString() {
    
    
        return "ConcretePrototype{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    @Override
    public ConcretePrototype clone() {
    
    
        try {
    
    
            return (ConcretePrototype)super.clone();
        } catch (CloneNotSupportedException e) {
    
    
            e.printStackTrace();
            return null;
        }
    }
}

2. Prueba

public class PrototypeTest {
    
    
    public static void main(String[] args) {
    
    
        //创建原型
        ConcretePrototype cp =new ConcretePrototype();
        cp.setName("tom");
        cp.setAge(21);
        System.out.println(cp);
        //拷贝原型
        ConcretePrototype cloneType=cp.clone();
        System.out.println(cloneType);
    }
}

Resultado de la operación:
Inserte la descripción de la imagen aquí
A continuación, agregamos atributos de pasatiempo en la clase ConcretePrototype:

public class PrototypeTest {
    
    
    public static void main(String[] args) {
    
    
        //创建原型
        ConcretePrototype cp =new ConcretePrototype();
        cp.setName("tom");
        cp.setAge(21);
        List<String>hobbies=new ArrayList<String>();
        hobbies.add("书法");
        hobbies.add("绘画");
        cp.setHobbies(hobbies);

        //拷贝原型
        ConcretePrototype cloneType=cp.clone();
        cloneType.getHobbies().add("游泳");
        System.out.println(cp);
        System.out.println(cloneType);
    }
}

Resultados: Después de
Inserte la descripción de la imagen aquí
agregar un pasatiempo al objeto copiado, descubrimos que el objeto prototipo también ha cambiado. Obviamente, esto no cumple con nuestras expectativas, porque esperamos que el objeto clonado y el objeto prototipo sean dos objetos independientes sin ninguna conexión. Tras el análisis, resulta que hobbies compartieron una dirección, es decir, se copió la dirección referenciada. Esto es lo que a menudo llamamos clon superficial.

Clon profundo

Realizado por serialización:

public class ConcretePrototype implements Serializable {
    
    
    int age;
    String name;
    List<String>hobbies;

    @Override
    public String toString() {
    
    
        return "ConcretePrototype{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", hobbies=" + hobbies +
                '}';
    }

    public List<String> getHobbies() {
    
    
        return hobbies;
    }

    public void setHobbies(List<String> hobbies) {
    
    
        this.hobbies = hobbies;
    }

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }


    public ConcretePrototype deepClone() {
    
    
        try {
    
    
            ByteArrayOutputStream bos=new ByteArrayOutputStream();
            ObjectOutputStream oos=new ObjectOutputStream(bos);
            oos.writeObject(this);

            ByteArrayInputStream bis=new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois=new ObjectInputStream(bis);
            return (ConcretePrototype)ois.readObject();
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return null;
        }
    }
}
public class PrototypeTest {
    
    
    public static void main(String[] args) {
    
    
        //创建原型
        ConcretePrototype cp =new ConcretePrototype();
        cp.setName("tom");
        cp.setAge(21);
        List<String>hobbies=new ArrayList<String>();
        hobbies.add("书法");
        hobbies.add("绘画");
        cp.setHobbies(hobbies);

        //拷贝原型
        ConcretePrototype cloneType=cp.deepClone();
        cloneType.getHobbies().add("游泳");
        System.out.println(cp);
        System.out.println(cloneType);
    }
}

Resultado de la operación:
Inserte la descripción de la imagen aquí
la clonación profunda destruirá el singleton, y la solución es muy simple: prohibir la clonación profunda. O nuestra clase singleton no implementa la interfaz Cloneable; o escribimos == clone ()Método enEl objeto singleton se puede devolver en el método clone () ==.

Usar en código fuente

Veamos primero la interfaz clonable:

public interface Cloneable {
    
    
}

La interfaz Cloneable es muy simple, echemos un vistazo a su clase de implementación. Por ejemplo, la implementación de la clase ArrayList:

public Object clone() {
    
    
        try {
    
    
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
    
    
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }

para resumir

ventaja

  1. Desempeño mejorado. El rendimiento de un objeto es mucho mejor que directamente nuevo
  2. Simplificó el proceso de creación de objetos.

Desventaja

  1. Necesita configurar un método de clonación para cada clase
  2. Cuando se modifica la clase existente, el código debe modificarse, lo que viola el principio de apertura y cierre.

Supongo que te gusta

Origin blog.csdn.net/xzw12138/article/details/106732206
Recomendado
Clasificación