设计模式--原型模式

一 应用场景

大学的时候毕业论文太难写了,所以直接抄同学的,但是这种你并不是一个字一个字的重写。而是使用cv大法(ctrl+c和ctrl+v),直接将毕业论文进行复制粘贴。然后自己就可以安心的去打游戏了。

原型模式是一种创建型模式,例如我们要创建一个Student对象都是采用的new Student();但是有些时候对象的创建十分复杂,这个时候原型模式就登场了,就像毕业论文太长了自己写太麻烦。所以我们选择复制。

二 实现原理

通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建,即 对象.clone()

uml

  • Prototype : 原型类,声明一个克隆自己的接口
  • ConcretePrototype: 具体的原型类, 实现一个克隆自己的操作
  • Client: 让一个原型对象克隆自己,从而创建一个新的对象(属性一样)

三 代码实现

申明原型类型 实现Cloneable接口

@Getter
@Setter
public class Student implements Cloneable {
   private String name;
   private String age;
   private Teacher teacher;

   @Override
   protected Student clone() throws CloneNotSupportedException {
       Student clone = (Student) super.clone();
       
       return clone;
   }
}


@Setter
@Getter
public class Teacher implements Cloneable{
   private String teacherName;

   @Override
   protected Teacher clone() throws CloneNotSupportedException {
       Teacher clone = (Teacher)super.clone();
       return clone;
   }
}

客户端调用原型拷贝

public class Client {
   @SneakyThrows
   public static void main(String[] args) {
       Student student = new Student();
       student.setAge("18");
       student.setName("小明");
       Teacher teacher = new Teacher();
       student.setTeacher(teacher);

       Student clone = student.clone();

       System.out.println(student);
       System.out.println(clone);
       System.out.println(clone.getTeacher());
       System.out.println(student.getTeacher());

   }
}

运行结果

com.cncloud.prototype.Student@19e1023e
com.cncloud.prototype.Student@7cef4e59

com.cncloud.prototype.Teacher@64b8f8f4
com.cncloud.prototype.Teacher@64b8f8f4

从上面的运行结果可以看出通过clone创建的对象是一个新对象(引用地址不一样),通过浅拷贝实现对新对象的属性值进行复制的

四 深拷贝和浅拷贝

浅拷贝

对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象

对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值

深拷贝

复制对象的所有基本数据类型的成员变量值

为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象进行拷贝

4.1 重写clone方法来实现深拷贝

@Getter
@Setter
public class Student implements Cloneable {
    private String name;
    private String age;
    private Teacher teacher;

    @Override
    protected Student clone() throws CloneNotSupportedException {
        Student clone = (Student) super.clone();
        Teacher teacher = clone.getTeacher().clone();//调用clone方法重新复制
        clone.setTeacher(teacher);
        return clone;
    }
}
@Setter
@Getter
public class Teacher implements Cloneable{
    private String teacherName;

    @Override
    protected Teacher clone() throws CloneNotSupportedException {
        Teacher clone = (Teacher)super.clone();
        return clone;
    }
}

public class Client {
    @SneakyThrows
    public static void main(String[] args) {
        Student student = new Student();
        student.setAge("18");
        student.setName("小明");
        Teacher teacher = new Teacher();
        student.setTeacher(teacher);

        Student clone = student.clone();

        System.out.println(student);
        System.out.println(clone);
        System.out.println(clone.getTeacher());
        System.out.println(student.getTeacher());

    }
}

运行结果:

com.cncloud.prototype.Student@19e1023e
com.cncloud.prototype.Student@7cef4e59
com.cncloud.prototype.Teacher@64b8f8f4
com.cncloud.prototype.Teacher@2db0f6b2

这种实现方式过于复杂,一般不使用

4.2 通过对象序列化实现深拷贝

@Getter
@Setter
public class Student implements Cloneable, Serializable {
    private String name;
    private String age;
    private Teacher teacher;

    @Override
    protected Student clone() throws CloneNotSupportedException {
        Student clone = (Student) super.clone();
        Teacher teacher = clone.getTeacher().clone();
        clone.setTeacher(teacher);
        return clone;
    }

    public Student serializableClone()  {
        //创建流对象
        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);
            Student copyObj = (Student)ois.readObject();

            return copyObj;
        } catch (Exception e) {
            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());
            }
        }
    }
}

public class Client {
    @SneakyThrows
    public static void main(String[] args) {
        Student student = new Student();
        student.setAge("18");
        student.setName("小明");
        Teacher teacher = new Teacher();
        student.setTeacher(teacher);
        Student serializableClone = student.serializableClone();

        System.out.println(student.getTeacher());
        System.out.println(serializableClone.getTeacher());

    }
}

运行结果:

com.cncloud.prototype.Teacher@3ecf72fd
com.cncloud.prototype.Teacher@5315b42e

五 总结

原型模式一般是解决对象的创建比较复杂的场景,原型模式优缺点如下

优点:能够解决复杂对象的创建,同时进行解耦,如果复杂的每次自己创建,再具体产品进行修改后,业务代码全部可能会进行调整。

缺点:每个具体的产品必须要实现Cloneable接口,同时如果要实现深拷贝实际上是比较复杂的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值