conceito
O padrão de protótipo se refere ao tipo de objeto criado pela instância do protótipo e cria novos objetos copiando esses protótipos. Ele pertence ao padrão do criador. O
padrão de protótipo inclui principalmente três funções:
- Cliente : a classe cliente fornece uma solicitação para criar um objeto
- Protótipo abstrato (protótipo) : especifique a interface de cópia
- Protótipo concreto : o objeto sendo copiado
Nota: O modo de criação de um objeto por meio da cópia do objeto em vez da nova palavra-chave é chamado de modo de protótipo
alcançar
Clone raso
Escrita padrão
1. Crie uma interface de protótipo
public interface IPrototype<T> {
T clone();
}
2. Crie um protótipo concreto
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. Teste
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 da operação:
neste momento, alguém perguntou, isso não é apenas copiar os atributos no objeto? Não é muito diferente do original. Na verdade, o processo de atribuição acima é feito por nós mesmos. Na codificação real, geralmente não desperdiçamos esse tipo de trabalho físico.
A seguir, veremos outra maneira de escrever o modo de protótipo
Implementar a interface clonável no JDK
O JDK nos ajudou a implementar uma API de thread, precisamos apenas implementar a interface de interface clonável.
1. Crie um protótipo concreto
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. Teste
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 da operação: a
seguir, adicionamos atributos de hobby na classe 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: Depois de
adicionar um hobby ao objeto copiado, descobrimos que o objeto de protótipo também mudou. Obviamente, isso não atende às nossas expectativas, pois esperamos que o objeto clonado e o objeto protótipo sejam dois objetos independentes sem qualquer conexão. Após análise, verifica-se que os hobbies compartilhavam um endereço, ou seja, o endereço referenciado foi copiado. Isso é o que costumamos chamar de clone raso
Clone profundo
Realizado por serialização:
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 da operação: a
clonagem profunda destruirá o singleton e a solução é muito simples: proibir a clonagem profunda. Ou nossa classe singleton não implementa a interface clonável ou escrevemos == clone ()Método emO objeto singleton pode ser retornado no método clone () ==.
Use no código-fonte
Vejamos primeiro a interface clonável:
public interface Cloneable {
}
A interface clonável é muito simples, vamos dar uma olhada em sua classe de implementação. Por exemplo, a implementação da classe 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);
}
}
Resumindo
vantagem
- Performance melhorada. O desempenho de um objeto é muito melhorado do que diretamente novo
- Simplificou o processo de criação de objetos
Desvantagem
- Precisa configurar um método clone para cada classe
- Quando a classe existente é modificada, o código precisa ser modificado, o que viola o princípio de abertura e fechamento