[Modo de design] ------ Modo de protótipo (cópia superficial e cópia profunda)

Modo de protótipo

O modo de protótipo é usar o objeto copiado para criar um novo objeto e não é necessário conhecer os detalhes da criação (como a atribuição de atributos da classe etc.).

Uso básico (cópia rasa)

É comum usar o método clone de Object. Você precisa fazer a classe implementar Cloneable e substituir o método clone para usá-lo.

public class A implements Cloneable{
    private String code;
    private String name;

    public A(String code, String name) {
        this.code = code;
        this.name = name;
    }

    public void setCode(String code) {
        this.code = code;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        A a = new A("00","name1");
        A a1 = (A)a.clone();
        a1.setCode("01");
        A a2 = (A)a.clone();
        a2.setCode("02");
        System.out.println(a.hashCode());
        System.out.println(a1.hashCode());
        System.out.println(a2.hashCode());
    }
}

Como resultado, fica claro que os três objetos são diferentes.

596512129
824318946
930990596

Cópia profunda

O método acima é uma cópia superficial, ou seja, apenas os tipos de dados básicos e String na Classe A podem ser copiados. Se houver outros tipos de referência na classe A, a cópia superficial não poderá realizar a cópia dos tipos de referência.
Portanto, você precisa executar uma cópia profunda de A. Geralmente, existem dois métodos (substituindo o método Clone e a serialização).

Método 1. Reescreva o método clone de A e copie B no método (é claro que a cópia superficial também deve ser implementada na classe B).

public class B implements Serializable,Cloneable{
    private String id;

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class A implements Serializable,Cloneable{
    private String code;
    private String name;
    private B b;

    public A(String code, String name, B b) {
        this.code = code;
        this.name = name;
        this.b = b;
    }

    public void setCode(String code) {
        this.code = code;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        A a = (A)super.clone();
        // 在A的clone方法中,对A的B引用进行clone
        a.b = (B)a.b.clone();
        return a;
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        A a = new A("00","name1",new B());
        A a1 = (A)a.clone();
        a1.setCode("01");
        A a2 = (A)a.clone();
        a2.setCode("02");
        System.out.println(a.b.hashCode());
        System.out.println(a1.b.hashCode());
        System.out.println(a2.b.hashCode());
    }
}
执行结果:
596512129
824318946
930990596

Observando o resultado da execução, a referência B de cada instância A é um valor hashCode diferente, indicando que o B em A também é copiado.
Se você comentar ab = (B) abclone (); no método clone em A, poderá obter que os três resultados impressos sejam os mesmos.

Método 2. Serialização

Premissa de serialização, A e B devem implementar a interface serializável.
As definições de A e B são as mesmas do método 1, apenas reescrevemos o método clone em A.

@Override
    public Object clone() throws CloneNotSupportedException {

        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);

            A copyResult = (A)ois.readObject();

            return copyResult;

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                bos.close();
                oos.close();
                bis.close();
                ois.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return null;
    }

O efeito final também é com o clone de A e a referência B em A também é clonada.
A serialização acima é apenas uma ideia de implementação.Você também pode usar o fastjson para converter o objeto A em uma string json e, em seguida, reverter para A. para retornar.De fato, o princípio é o mesmo.

Cenários de aplicativos reais

De fato, é fácil encontrar: desde que você descubra quais classes implementam a interface Cloneable, o chamado modo protótipo é usado com maior probabilidade.

Por exemplo, na criação do Spring's Bean, todos sabemos que o padrão é o modo singleton; na verdade, você também pode saber que o Bean é multi-case, isso usa o modo prototype.

Publicado 203 artigos originais · elogiado 186 · 210.000 visualizações

Acho que você gosta

Origin blog.csdn.net/java_zhangshuai/article/details/105236908
Recomendado
Clasificación