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
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:
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
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:
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
- Desempeño mejorado. El rendimiento de un objeto es mucho mejor que directamente nuevo
- Simplificó el proceso de creación de objetos.
Desventaja
- Necesita configurar un método de clonación para cada clase
- Cuando se modifica la clase existente, el código debe modificarse, lo que viola el principio de apertura y cierre.