设计模式-原型模式

Posted wenq001

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式-原型模式相关的知识,希望对你有一定的参考价值。

原型模式概念:

 所谓原型模式就是用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象的过程。

原型模式的使用:

 在java中实现原形模式主要通过实现 Cloneable 接口,重新clone方法实现。

package com.dsx.design.prototype;

import java.io.Serializable;
import java.util.Date;

public class Student implements Serializable ,Cloneable {

    private String name ;
    private Integer age ;
    private Date birthday ;

    private Teacher teacher ;

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name=‘" + name + ‘\\‘‘ +
                ", age=" + age +
                ", birthday=" + birthday +
                ", teacher=" + teacher +
                ‘}‘;
    }

    /**
     * 浅拷贝
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

 

需要获取新对象的时候,可以先new一个实例, 然后通过实例的clone方法获取新的拷贝对象。

技术图片

如图,调用student实例的clone方法获取新的拷贝对象。

但是使用原型模式有个点需要注意:
注意!!!!!!!!!

如上图代码所示:debug情况如下:

技术图片

修改了teacher对象的Age信息,原对象和新拷贝的对象的属性的值都变成了新值。从上图中也可以看出,两个对象的属性teacher的地址相同。这是因为实现cloneable接口属于浅拷贝。

深拷贝和浅拷贝的概念:

浅拷贝:

被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。即对象的浅拷贝会对“主”对象进行拷贝,但不会复制主对象里面的对象。”里面的对象“会在原来的对象和它的副本之间共享。

简而言之,浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象。白话理解:浅拷贝就是说新产生的对象和原来对象的地址是不一样的,但是如果原来对象里面包含引用对象,拷贝完之后的新对象属性中的引用对象不会创建新的,还是和原先对象的属性中引用对象指向同一地址。

图示:

技术图片

 

Student的拷贝,创建了新对象stu1,stu2,但是对象里面Teacher属性,stu1和stu2还是指向同一个Teacher地址。

深拷贝:

深拷贝是一个整个独立的对象拷贝,深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。

简而言之,深拷贝把要复制的对象所引用的对象都复制了一遍。白话理解:和浅拷贝对应起来理解,不仅是拷贝的对象是新对象,如果对象里面的属性是引用对象,那么拷贝对象的引用属性也是新对象。

 图示:
技术图片

如上:深拷贝,不仅stu1和stu2是新对象,两个对象的属性teacher也是不同的地址引用.

原型模式中属于浅拷贝还是深度拷贝?

  原型模式是属于浅拷贝 。

原型模式中如何实现深度拷贝?

 圆形模式中如果需要实现深度拷贝,则需要对对象的属性都进行拷贝。

方式1:重写clone方法的时候,需要对每一个引用对象都重新赋值,例如Teacher的赋值

在student的 clone方法中重写Date和Teacher的拷贝:

    /**
     * 深度拷贝
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Student student = (Student) super.clone();
        student.setTeacher((Teacher) student.getTeacher().clone());
        student.setBirthday((Date) student.getBirthday().clone());
        return  student ;
    }

当然如果对象的属性很多,我们也可以对对象实现Serializable ,使用序列化实现深拷贝:

 public Object deepClone() throws Exception { 
  // 序列化
  ByteArrayOutputStream bos = new ByteArrayOutputStream();
  ObjectOutputStream oos = new ObjectOutputStream(bos);
  oos.writeObject(this);
  // 反序列化
  ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
  ObjectInputStream ois = new ObjectInputStream(bis);
  return ois.readObject();
}

 

 

附上该设计模式中的测试代码;

Student 类:

package com.dsx.design.prototype;

import java.io.Serializable;
import java.util.Date;

public class Student implements Serializable ,Cloneable {

    private String name ;
    private Integer age ;
    private Date birthday ;

    private Teacher teacher ;

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name=‘" + name + ‘\\‘‘ +
                ", age=" + age +
                ", birthday=" + birthday +
                ", teacher=" + teacher +
                ‘}‘;
    }

    /**
     * 浅拷贝
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

//
//    /**
//     * 深度拷贝
//     * @return
//     * @throws CloneNotSupportedException
//     */
//    @Override
//    protected Object clone() throws CloneNotSupportedException {
//        Student student = (Student) super.clone();
//        student.setTeacher((Teacher) student.getTeacher().clone());
//        student.setBirthday((Date) student.getBirthday().clone());
//        return  student ;
//    }
}

Teacher 类:

package com.dsx.design.prototype;


public class Teacher implements  Cloneable{

    private String name ;
    private Integer age ;

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "name=‘" + name + ‘\\‘‘ +
                ", age=" + age +
                ‘}‘;
    }


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

Test 类:

package com.dsx.design.prototype;

import java.util.Date;

public class Test {

    public static void main(String[] args) throws CloneNotSupportedException {

        Student student = new Student();
        Date date = new Date(666666L);
        student.setName("zhangsan");
        student.setBirthday(date);

        Teacher teacher = new Teacher();
        teacher.setName("李老师");
        teacher.setAge(38);
        student.setTeacher(teacher);
        Student clone = (Student) student.clone();
        teacher.setAge(40);
        System.out.println(student);

    }
}

 

以上是关于设计模式-原型模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式之原型模式(Prototype)详解及代码示例

设计模式课程 设计模式精讲 9-2 原型模式coding

设计模式--原型模式

设计模式原型模式

Java设计模式----原型模式

设计模式--------原型模式