原型模式
创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,
应用场景
创建复杂的对象而且创建过程特别长,且内容基本都相同,
比如json的解析还原对象的过程,先将对象转化成json形式的字符串,然后再将字符串转化成对象,如果采用构造方法的方式进行创建,则需要了解每个函数的构造方法进行创建或者进行setter
优点
可以快速的相同的对象,性能比重新创建对象高
缺点
需要实现Cloneable接口,对于已经存在的类来说,改造成本会增大,会影响原来的逻辑
浅拷贝
浅拷贝是指在复制对象过程中,只将基础类型还包括String 以及基本类型的包装类型的对象复制过来,但是引用类型的还是指向原来对象的内存 ,因此两种对象中如果任意改变引用类型的对象的值,两边的值都会被改变,如果用== 或者equal来进行整个对象的比较地址值是不相同的
深拷贝
深拷贝是指在复制对象过程中,将新的对象完全开辟一个新的内存去存储新的对象,原来或者克隆对象的改变都不会引起双方值的变化,在java中使用流的方式来实现这种深拷贝
测试代码
公共对象
user类
package com.example.demo.study.prototype;
import java.io.*;
/**
* @Author zhanpeng
* @Date 2023/5/23 9:11
*/
public class User implements Cloneable, Serializable {
private String name;
private int age ;
private Integer high;
private Phone phone;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Integer getHigh() {
return high;
}
public void setHigh(Integer high) {
this.high = high;
}
public Phone getPhone() {
return phone;
}
public void setPhone(Phone phone) {
this.phone = phone;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", high=" + high +
", phone=" + phone +
'}';
}
@Override
public User clone() {
try {
User clone = (User) super.clone();
/*// 这一部分是将对象进行深拷贝,当调用clone的方法时默认返回的是深拷贝后的对象
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(this);
objectOutputStream.flush();
ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));
clone = (User)objectInputStream.readObject();
objectInputStream.close();
objectOutputStream.close();*/
return clone;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
}
phone 类
package com.example.demo.study.prototype;
import java.io.Serializable;
/**
* @Author zhanpeng
* @Date 2023/5/24 8:50
*/
public class Phone implements/* Cloneable*/ Serializable {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Phone{" +
"name='" + name + '\'' +
'}';
}
/* @Override
public Phone clone() {
try {
Phone clone = (Phone) super.clone();
// TODO: copy mutable state here, so the clone can't change the internals of the original
return clone;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}*/
}
测试代码
拷贝测试类,如果只需要浅拷贝,就使用上述代码即可,如果需要深拷贝 放开user类中在clone方法中注释的代码
public static void main(String[] args){
//浅克隆
User user = new User();
user.setAge(3);
user.setName("333");
user.setHigh(130);
Phone phone = new Phone();
phone.setName("苹果");
user.setPhone(phone);
User clone = user.clone();
clone.setAge(2);
clone.setName("222");
clone.setHigh(120);
clone.getPhone().setName("安卓");
/*Phone phone2 = new Phone();
phone2.setName("安卓");
clone.setPhone(phone2);*/
System.out.println("clone.equals(user) = " + clone.equals(user));
System.out.println(clone == user);
System.out.println("user = " + user);
System.out.println("clone = " + clone);
}
测试结果
浅拷贝的测试结果,可以看到 引用类型的对象被变得完全一样了,但是其他的类型的都正常的改变了
clone.equals(user) = false
false
user = User{name='333', age=3, high=130, phone=Phone{name='安卓'}}
clone = User{name='222', age=2, high=120, phone=Phone{name='安卓'}}
深拷贝的测试结果,可以看到双方任意对象的改变都不会影响彼此
#深拷贝的测试结果
clone.equals(user) = false
false
user = User{name='333', age=3, high=130, phone=Phone{name='苹果'}}
clone = User{name='222', age=2, high=120, phone=Phone{name='安卓'}}
原型管理
简单原型管理
比如我需要创建一个User类,但是我不想在运行时在去创建,那样可能会很耗时,我想在加载的时候就创建成功,然后提供一个克隆方法来实现管理
package com.example.demo.study.prototype;
/**
* @Author zhanpeng
* @Date 2023/5/25 7:57
*/
public enum PrototypeManager {
//一个单例模式的原型工厂,来控制克隆对象
INSTANCE;
private static final User user = new User();
//默认初始化一个user对象,用于提供复制
static {
user.setAge(3);
user.setName("333");
user.setHigh(130);
Phone phone = new Phone();
phone.setName("苹果");
user.setPhone(phone);
}
//输出复制的对象的方法
public User getCloneUser() {
return user.clone();
}
}
测试
@Test
public void test1 () {
User cloneUser = PrototypeManager.INSTANCE.getCloneUser();
System.out.println("cloneUser = " + cloneUser);
}
测试结果
cloneUser = User{name='333', age=3, high=130, phone=Phone{name='苹果'}}
通用管理
这个管理器我想更通用一点,比如定义一个PEOPLE的接口,然后继承Cloneable,只要实现了POEPLE的类我都可以进行管理,这里我定义了一个Student 和一个Teacher老师类来实现PEOPLE这个接口然后进行原型管理
people接口
package com.example.demo.study.prototype;
/**
* @Author zhanpeng
* @Date 2023/5/25 8:07
*/
public interface People extends Cloneable{
//定义一个 克隆people接口
People clone() throws CloneNotSupportedException;
}
学生类
package com.example.demo.study.prototype;
/**
* @Author zhanpeng
* @Date 2023/5/25 8:15
*/
public class Student implements People{
private String name;
private int age ;
private Integer high;
private Phone phone;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Integer getHigh() {
return high;
}
public void setHigh(Integer high) {
this.high = high;
}
public Phone getPhone() {
return phone;
}
public void setPhone(Phone phone) {
this.phone = phone;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", high=" + high +
", phone=" + phone +
'}';
}
@Override
public Student clone(){
try {
Student clone = (Student) super.clone();
return clone;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
老师类
package com.example.demo.study.prototype;
/**
* @Author zhanpeng
* @Date 2023/5/25 8:19
*/
public class Teacher implements People{
private String name;
private int age ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public Teacher clone() throws CloneNotSupportedException {
try {
Teacher clone = (Teacher) super.clone();
return clone;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
}
原型管理器
package com.example.demo.study.prototype;
import java.util.HashMap;
import java.util.Map;
/**
* @Author zhanpeng
* @Date 2023/5/25 7:57
*/
public enum PrototypeManager2 {
INSTANCE;
public enum PeopleType {
STU,TEA;
}
//一个单例模式的原型工厂,来控制克隆对象
private static final Map<String, People> clones = new HashMap<String, People>();
//初始化需要克隆的对象,此处展示的是简单对象,如果项目上有复制对象可以再启动环节就进行创建好,然后后续直接克隆使用
static {
Student student = new Student();
student.setAge(8);
student.setName("狗蛋");
student.setHigh(130);
Phone phone = new Phone();
phone.setName("小苹果手机");
student.setPhone(phone);
clones.put(PeopleType.STU.name(), student);
Teacher teacher = new Teacher();
teacher.setAge(33);
teacher.setName("小王老师");
clones.put(PeopleType.TEA.name(), teacher);
}
//输出复制的对象的方法
public People getClonePeople(PeopleType type) {
try {
return clones.get(type.name()).clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
测试类
@Test
public void test2 () {
People cloneStudent = PrototypeManager2.INSTANCE.getClonePeople(PrototypeManager2.PeopleType.STU);
People cloneTeacher = PrototypeManager2.INSTANCE.getClonePeople(PrototypeManager2.PeopleType.TEA);
System.out.println("cloneStudent = " + cloneStudent);
System.out.println("cloneTeacher = " + cloneTeacher);
}
测试结果
cloneStudent = Student{name='狗蛋', age=8, high=130, phone=Phone{name='小苹果手机'}}
cloneTeacher = Teacher{name='小王老师', age=33}