美文网首页
设计模式之原型模式

设计模式之原型模式

作者: Tinyspot | 来源:发表于2023-02-07 21:24 被阅读0次

1. 原型模式

  • 对原型进行拷贝来创建新对象
  • 原型模式的两种实现方法
    • 浅拷贝
    • 深拷贝

1.2 核心组成

  • IPrototype
  • ConcretePrototype
  • Client

1.3 应用场景

  • 创建新对象成本较大,新的对象可以通过原型模式对已有对象进行复制来获得

1.4 浅拷贝与深拷贝区别

  • 浅拷贝得到的对象跟原始对象共享数据,而深拷贝会复制数据本身
  • 浅拷贝只会复制对象中基本数据类型数据和引用对象的内存地址,不会递归地复制引用对象,以及引用对象的引用对象……而深拷贝得到的是一份完完全全独立的对象

2. 浅拷贝

  • 实现 Cloneable 接口
  • 重写 clone()
  • 基本数据类型可以达到完全复制,引用数据类型不可以,因为引用数据类型仅仅是拷贝了一份引用
public void demo() {
    ArrayList<String> list = new ArrayList<>();
    list.add("AAA");
    list.add("BBB");

    Object copyList = list.clone();
    System.out.println(copyList == list);
    System.out.println(copyList);
    // 结果是false, 但内容是一样的
}

2.2 对象复制

@Test
public void test() {
    Course course = new Course("English");
    Student student = new Student("Tinyspot", 20, course);

    Student stu2 = new Student();
    stu2.setName(student.getName());
    stu2.setAge(student.getAge());
    stu2.setCourse(student.getCourse());

    student.setName("222");
    student.setAge(22);
    student.getCourse().setTitle("Chinese");
    // or course.setTitle("Chinese");
    System.out.println(student.getCourse() == stu2.getCourse()); // true
}

打印对象:
student: Student(name=222, age=22, course=Course(title=Chinese))
stu2: Student(name=Tinyspot, age=20, course=Course(title=Chinese))

2.3 浅拷贝示例

  • 浅拷贝的引用类型会随原型对象(拷贝对象)改变而改变
  • 实现 Cloneable 接口
@Test
public void test() throws CloneNotSupportedException {
    Student student = new Student("Tinyspot", 20, new Course("English"));
    Student stuCopy = student.clone();

    student.setAge(22);
    stuCopy.getCourse().setTitle("Chinese");
}

打印对象:
student: Student(name=Tinyspot, age=22, course=Course(title=Chinese))
stuCopy: Student(name=Tinyspot, age=20, course=Course(title=Chinese))

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student implements Cloneable {
    private String name;
    private Integer age;
    private Course course;

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

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Course {
    private String title;
}

3. 深拷贝

  • 递归拷贝对象、对象的引用对象以及引用对象的引用对象……直到要拷贝的对象只包含基本数据类型数据,没有引用对象为止

3.1 实现方式一

  • 引用类型也实现Cloneable, 重写 clone()
  • 当对象之间存在多重嵌套引用,每一层对象对应的类都必须支持深克隆
@Test
public void test() throws CloneNotSupportedException {
    Student student = new Student("Tinyspot", 20, new Course("English"));
    Student stuCopy = student.clone();
    
    student.setAge(22);
    student.getCourse().setTitle("Chinese");
}

打印对象:
student: Student(name=Tinyspot, age=22, course=Course(title=Chinese))
stuCopy: Student(name=Tinyspot, age=20, course=Course(title=English))

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student implements Cloneable {
    private String name;
    private Integer age;
    private Course course;

    @Override
    public Student clone() throws CloneNotSupportedException {
        Student student = (Student) super.clone();
        // 将拷贝出的对象赋给成员变量
        // or student.course = this.course.clone();
        student.setCourse(this.course.clone());
        return student;
    }
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Course implements Cloneable {
    private String title;

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

3.2 实现方式二

  • 先将对象序列化,然后再反序列化成新的对象
  • Serializable 读取二进制流
@Test
public void test() throws CloneNotSupportedException {
    Person person = new Person();
    person.setName("Tinyspot");
    person.getList().add("AAA");

    // 测试浅拷贝
    Person personCopy = person.clone();

    person.setName("222");
    person.getList().add("BBB");
    // or personCopy.getList().add("BBB");

    System.out.println("person: " + person);
    System.out.println("personCopy: " + personCopy);
    System.out.println(person.getList() == personCopy.getList()); // true
}

打印对象:
person: Person(name=222, age=null, list=[AAA, BBB])
personCopy: Person(name=Tinyspot, age=null, list=[AAA, BBB])

@Test
public void test() {
    Person person = new Person();
    person.setName("Tinyspot");
    person.getList().add("AAA");

    // 测试深拷贝
    Person personCopy = person.deepClone();
    personCopy.getList().add("BBB");
}

打印对象
person: Person(name=Tinyspot, age=null, list=[AAA])
personCopy: Person(name=Tinyspot, age=null, list=[AAA, BBB])

相关文章

网友评论

      本文标题:设计模式之原型模式

      本文链接:https://www.haomeiwen.com/subject/iaufkdtx.html