飞道的博客

原型模式

459人阅读  评论(0)

什么是原型模式

在GOF的《设计模式:可复用面向对象软件的基础》中是这样说的:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。在这个定义中,最重要的一个词是“拷贝”,也就是口头上的复制,而这个拷贝,也就是原型模式的精髓所在。

简而言之就是复制一个已有的对象,复制的新对象的属性和已有对象完全一致

原型模式的优缺点

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

原型模式的几种分类

1.浅拷贝:简单数据类型的成员属性复制一份,复杂数据类型成员属性引用已有的实例的属性
2.深拷贝(有两种实现方式):所有属性都复制一份
        1)重写clone()方法手动拷贝各复杂数据类型成员属性
        2)使用序列化实现深拷贝

浅拷贝

代码:

public class Type01 {
    public static void main(String[] args){
        Student s1=new Student("张三");
        Student s2=new Student("李四");
        s1.setFriend(s2);
        Student s3= (Student) s1.clone();
        System.out.println(s1==s2);
        System.out.println(s1.getFriend()==s3.getFriend());
    }
}

class Student implements Cloneable{
    private String name;

    public String getName() {
        return name;
    }

    public Student getFriend() {
        return friend;
    }

    private Student friend;

    public Student(String name) {
        this.name = name;
    }

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

    public void setFriend(Student friend) {
        this.friend = friend;
    }

    @Override
    public Object clone()  {
        Object o=null;
        try {
            o=super.clone();
        }catch (Exception e){
            e.printStackTrace();
        }
        return o;
    }
}


输出:

false
true

注意:
1.必须重写clone()方法,因为父类的clone()方法的修饰符是protected的
2.建议将重写的clone()方法修饰符改为public,避免其他包的类无法访问
3.不实现Cloneable接口会报CloneNotSupportedException异常
4.被拷贝的对象的复杂类型属性不会创建新的,而是引用已有的

深拷贝一 (手动拷贝)

代码:

public class Type02 {
    public static void main(String[] args){
        Student s1=new Student("张三");
        Student s2=new Student("李四");
        s1.setFriend(s2);
        Student s3= (Student) s1.clone();
        System.out.println(s1==s2);
        System.out.println(s1.getFriend()==s3.getFriend());
    }
}

class Student implements Cloneable{
    private String name;

    public String getName() {
        return name;
    }

    public Student getFriend() {
        return friend;
    }

    private Student friend;

    public Student(String name) {
        this.name = name;
    }

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

    public void setFriend(Student friend) {
        this.friend = friend;
    }

    @Override
    public Object clone()  {
        Student o=null;
        try {
            o=(Student)super.clone();
        }catch (Exception e){
            e.printStackTrace();
        }
        Student f=null;
        //例子举得不太好,递归了,this.friend.friend是null,所以加个判断,避免空指针异常
        if (this.friend != null) {
            f=(Student)this.friend.clone();
        }
        o.setFriend(f);
        return o;
    }
}

输出:

false
false

注意: 显然这很麻烦,无限套娃,实用性较低

深拷贝二(使用序列化)

代码:

import java.io.*;
public class Type03 {
    public static void main(String[] args){
        Student s1=new Student("张三");
        Student s2=new Student("李四");
        s1.setFriend(s2);
        Student s3= (Student) s1.clone();
        System.out.println(s1.getName());
        System.out.println(s3.getName());
        System.out.println(s1.getFriend().getName());
        System.out.println(s3.getFriend().getName());
        System.out.println(s1==s2);
        System.out.println(s1.getFriend()==s3.getFriend());
    }
}

class Student implements Cloneable, Serializable {
    private String name;

    public String getName() {
        return name;
    }

    public Student getFriend() {
        return friend;
    }

    private Student friend;

    public Student(String name) {
        this.name = name;
    }

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

    public void setFriend(Student friend) {
        this.friend = friend;
    }

    @Override
    public Object clone()  {
        Object o=null;
        ObjectOutputStream oos;
        ObjectInputStream ois;
        ByteArrayOutputStream bos;
        ByteArrayInputStream bis;
        try {
            bos=new ByteArrayOutputStream();
            oos=new ObjectOutputStream(bos);
            oos.writeObject(this);
            bis=new ByteArrayInputStream(bos.toByteArray());
            ois=new ObjectInputStream(bis);
            o = ois.readObject();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (ois == null) {
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bis == null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (oos == null) {
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bos == null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return o;
    }
}

输出:

张三
张三
李四
李四
false
false

推荐使用这种方式


转载:https://blog.csdn.net/m0_47553984/article/details/106177132
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场