Un patrón de diseño al día: prototipo

Uno: definición de modo

** El patrón de prototipo se utiliza para crear objetos duplicados manteniendo el rendimiento. **Este tipo de patrón de diseño es un patrón de creación, que proporciona una forma óptima de crear objetos.

Este patrón implementa una interfaz prototipo que se utiliza para crear un clon del objeto actual . Este modo se usa cuando el costo de crear directamente el objeto es relativamente alto. Por ejemplo, es necesario crear un objeto después de una costosa operación de base de datos. Podemos reducir las llamadas a la base de datos almacenando en caché el objeto, devolviendo un clon del mismo en la siguiente solicitud y actualizando la base de datos cuando sea necesario. Es decir: use una instancia de prototipo para especificar el tipo de objeto a crear y cree un nuevo objeto copiando este prototipo.

Dos: estructura del patrón

El modo Arquetipo incluye los siguientes roles:

  • Prototipo : clase de prototipo
  • ConcretePrototype: clase de prototipo de hormigón
    inserte la descripción de la imagen aquí

Tres: Aplicación - Problema de clonación de ovejas

Ahora hay una oveja tom, nombre: tom, edad: 1, color: blanco, escriba un programa para crear 10 ovejas con los mismos atributos que tom
sheep.
La forma tradicional de resolver el problema de la clonación de ovejas:

package com.atguigu.prototype;

public class Client {
    
    

public static void main(String[] args) {
    
    
// TODO Auto-generated method stub
//传统的方法
Sheep sheep = new Sheep("tom", 1, "白色");

Sheep sheep2 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor()); Sheep sheep3 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor()); Sheep sheep4 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
 

Sheep sheep5 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
//....

System.out.println(sheep); System.out.println(sheep2); System.out.println(sheep3); System.out.println(sheep4); System.out.println(sheep5);
//...
}

}

Ventajas y desventajas de los métodos tradicionales:

  1. La ventaja es que es más fácil de entender y fácil de operar.
  2. Al crear un nuevo objeto, siempre es necesario volver a adquirir las propiedades del objeto original, si el objeto creado es complejo, la eficiencia es baja.
  3. Siempre es necesario reiniciar el objeto en lugar de obtener dinámicamente el estado de tiempo de ejecución del objeto, no lo suficientemente flexible
  4. Análisis de ideas mejorado

Idea: La clase Object en Java es la clase raíz de todas las clases. La clase Object proporciona un método clone(), que puede copiar un objeto Java, pero la clase Java que necesita implementar clon debe implementar una interfaz Clonable, esta interfaz indica que la clase se puede copiar y tiene la capacidad de copiar => modo prototipo

Modo prototipo para crear ovejas clonadas:

Clase de ovejas:

public class Sheep implements Cloneable {
    
    
	private String name;
	private int age;
	private String color;
	private String address = "蒙古羊";
	public Sheep friend; // 是对象, 克隆是会如何处理, 默认是浅拷贝

	public Sheep(String name, int age, String color) {
    
    
		super();
		this.name = name;
		this.age = age;
		this.color = color;
	}

	public String getName() {
    
    
		return name;
	}

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

	public int getAge() {
    
    
		return age;
	}

	public void setAge(int age) {
    
    

		this.age = age;
	}

	public String getColor() {
    
    
		return color;
	}

	public void setColor(String color) {
    
    
		this.color = color;
	}

	@Override
	public String toString() {
    
    
		return "Sheep [name=" + name + ", age=" + age + ", color=" + color + ", address=" + address + "]";
	}

//克隆该实例,使用默认的 clone 方法来完成
	@Override
	protected Object clone() {
    
    

		Sheep sheep = null;
		try {
    
    
			sheep = (Sheep) super.clone();
		} catch (Exception e) {
    
    
// TODO: handle exception System.out.println(e.getMessage());
		}

// TODO Auto-generated method stub return sheep;
	}

}

Clase de cliente:

public class Client {
    
    

	public static void main(String[] args) {
    
    
		System.out.println("原型模式完成对象的创建");
// TODO Auto-generated method stub
		Sheep sheep = new Sheep("tom", 1, "白色");

		sheep.friend = new Sheep("jack", 2, "黑色");

		Sheep sheep2 = (Sheep) sheep.clone(); // 克隆Sheep sheep3 = (Sheep)sheep.clone(); //克隆Sheep sheep4 =
												// (Sheep)sheep.clone(); //克隆Sheep sheep5 = (Sheep)sheep.clone(); //克隆

		System.out.println("sheep2 =" + sheep2 + "sheep2.friend=" + sheep2.friend.hashCode());

		System.out.println("sheep3 =" + sheep3 + "sheep3.friend=" + sheep3.friend.hashCode());
		System.out.println("sheep4 =" + sheep4 + "sheep4.friend=" + sheep4.friend.hashCode());
		System.out.println("sheep5 =" + sheep5 + "sheep5.friend=" + sheep5.friend.hashCode());
	}

}

Cuatro: copia profunda y copia superficial

Copia superficial:

  1. Para una variable miembro cuyo tipo de datos es un tipo de datos básico, la copia superficial pasará directamente el valor, es decir, copiará el valor del atributo a un nuevo objeto.
  2. Para una variable miembro cuyo tipo de datos es un tipo de datos de referencia, por ejemplo, una variable miembro es una matriz, un objeto de cierta clase, etc., la copia superficial se pasará por referencia, es decir, solo el valor de referencia. (dirección de memoria) de la variable miembro será copiada, una para el nuevo objeto. Porque, de hecho, las variables miembro de ambos objetos apuntan a la misma instancia. En este caso, modificar la variable miembro en un objeto afectará el valor de la variable miembro en el otro objeto.

Cuando hay un objeto de oveja en el atributo de oveja clonado, cuando la oveja se clona varias veces, la referencia del objeto de atributo apuntará a la misma dirección.
Copia profunda:

  1. Copie los valores de las variables miembro de todos los tipos de datos primitivos de un objeto

  2. Asigne espacio de almacenamiento para todas las variables miembro del tipo de datos de referencia y copie los objetos a los que hace referencia cada variable miembro del tipo de datos de referencia hasta que el objeto pueda acceder a todos los objetos. Es decir, la copia profunda de un objeto requiere una copia del objeto completo (incluido el tipo de referencia del objeto)

  3. Implementación de copia profunda 1: anular el método de clonación para implementar una copia profunda

  4. Implementación de copia profunda 2: copia profunda mediante serialización de objetos (recomendado)
    Ejemplo de código:

public class DeepCloneableTarget implements Serializable, Cloneable {
    
    

	/**
	 
	
	*
	*/
	private static final long serialVersionUID = 1L;

	private String cloneName;

	private String cloneClass;

//构造器
	public DeepCloneableTarget(String cloneName, String cloneClass) {
    
    
		this.cloneName = cloneName;
		this.cloneClass = cloneClass;
	}

//因为该类的属性,都是 String ,  因此我们这里使用默认的 clone 完成即可
	@Override
	protected Object clone() throws CloneNotSupportedException {
    
    
		return super.clone();
	}
}

public class DeepProtoType implements Serializable, Cloneable {
    
    

	public String name; // String 属 性
	public DeepCloneableTarget deepCloneableTarget;// 引用类型

	public DeepProtoType() {
    
    
		super();
	}

//深拷贝 - 方式 1  使用 clone 方法
@Override
protected Object clone() throws CloneNotSupportedException {
    
    


Object deep = null;
//这里完成对基本数据类型(属性)和 String 的克隆
deep = super.clone();
//对引用类型的属性,进行单独处理
DeepProtoType deepProtoType = (DeepProtoType)deep;
deepProtoType.deepCloneableTarget	= (DeepCloneableTarget)deepCloneableTarget.clone();

// TODO Auto-generated method stub return deepProtoType;
 

}

//深拷贝 - 方式 2 通过对象的序列化实现 (推荐) public Object deepClone() {
    
    
//创建流对象ByteArrayOutputStream bos = null; ObjectOutputStream oos = null; ByteArrayInputStream bis = null; ObjectInputStream ois = null;

	try

	{
    
    

//序列化
		bos = new ByteArrayOutputStream();
		oos = new ObjectOutputStream(bos);
		oos.writeObject(this); // 当前这个对象以对象流的方式输出

//反序列化
		bis = new ByteArrayInputStream(bos.toByteArray());
		ois = new ObjectInputStream(bis);
		DeepProtoType copyObj = (DeepProtoType) ois.readObject();

		return copyObj;

	}catch(
	Exception e)
	{
    
    
// TODO: handle exception e.printStackTrace();
		return null;
	}finally
	{
    
    
//关闭流 try {
    
    
		bos.close();
		oos.close();
		bis.close();
		ois.close();
	}catch(Exception e2)
	{
    
    
// TODO: handle exception System.out.println(e2.getMessage());
	}
}

}

}

//Client.java
package com.atguigu.prototype.deepclone;


public class Client {
    
    
 

public static void main(String[] args) throws Exception {
    
    
// TODO Auto-generated method stub DeepProtoType p = new DeepProtoType(); p.name = "宋江";
p.deepCloneableTarget = new DeepCloneableTarget("大牛", "小牛");

//方式 1  完成深拷贝


//	DeepProtoType p2 = (DeepProtoType) p.clone();
//
//	System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());
//	System.out.println("p2.name=" + p.name + "p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode());

//方式 2  完成深拷贝
DeepProtoType p2 = (DeepProtoType) p.deepClone();


System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode()); System.out.println("p2.name=" + p.name + "p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode());

}


}

Pros y contras del modo prototipo:

1)	创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率
2)	不用重新初始化对象,而是动态地获得对象运行时的状态
3)	如果原始对象发生变化(增加或者减少属性),其它克隆对象的也会发生相应的变化,无需修改代码
4)	在实现深克隆的时候可能需要比较复杂的代码
5)	缺点:需要为每一个类配备一个克隆方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改其源代码,违背了 ocp 原则,这点请同学们注意.

Supongo que te gusta

Origin blog.csdn.net/qq_44867340/article/details/117885702
Recomendado
Clasificación