目录
java23种设计模式—— 一、设计模式介绍
java23种设计模式—— 二、单例模式
java23种设计模式——三、工厂模式
java23种设计模式——四、原型模式
java23种设计模式——四、原型模式
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
举个例子,就是当我们需要给电脑安装win10系统时需要去官网上下载win10系统的安装包。而安装包的大小都是很耗时的,还需要另一台电脑来操作。如果我们下载了一个安装包放在我们的u盘里,之后需要安装win10时是不是就省去了中间寻找,下载等时间呢
原型模式的克隆分为浅克隆和深克隆,Java 中的 Object 类提供了浅克隆的 clone() 方法,具体原型类只要实现 Cloneable 接口就可实现对象的浅克隆,这里的 Cloneable 接口就是抽象原型类。其代码如下
浅克隆
新建一个实体类Sheep实现Cloneable 接口,重写clone()方法
/**
* @author codermy
* @createTime 2020/5/14
*/
public class Sheep implements Cloneable{
private String name;
private int age;
private String sex;
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 String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Sheep(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
//克隆该实例,使用默认的clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
Sheep sheep =null;
sheep = (Sheep)super.clone();
return sheep;
}
}
测试
/**
* @author codermy
* @createTime 2020/5/14
*/
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Sheep sheep = new Sheep("tom",1,"male");
Sheep sheep1 = (Sheep)sheep.clone();
System.out.println(sheep.hashCode());
System.out.println(sheep);
System.out.println(sheep1.hashCode());
System.out.println(sheep1);
sheep1.setAge(2);
System.out.println(sheep1);
System.out.println(sheep);
}
}
输出
1163157884
Sheep{name='tom', age=1, sex='male'}
1956725890
Sheep{name='tom', age=1, sex='male'}
Sheep{name='tom', age=2, sex='male'}
Sheep{name='tom', age=1, sex='male'}
在浅克隆中,被复制对象的所有普通成员变量都具有与原来对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。也就是说,浅克隆仅仅复制所考虑的对象,不会复制它所引用的成员对象。
我们先新建一个Pearson类,作为对象属性
/**
* @author codermy
* @createTime 2020/7/24
*/
public class Person implements Cloneable{
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person(){
}
public Person(String name){
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
我们先给Sheep实体类种添加一个对象属性
/**
* @author codermy
* @createTime 2020/6/16
*/
public class Sheep implements Cloneable {
private String name;
private int age;
private String sex;
public Person owner;//对象引用
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 String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Person getOwner() {
return owner;
}
public void setOwner(Person owner) {
this.owner = owner;
}
public Sheep(String name, int age, String sex, Person owner) {
this.name = name;
this.age = age;
this.sex = sex;
this.owner = owner;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", owner=" + owner +
'}';
}
//克隆该实例,使用默认的clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
Sheep sheep =null;
sheep = (Sheep)super.clone();
return sheep;
}
}
测试类中测试
/**
* @author codermy
* @createTime 2020/6/16
*/
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Person owner = new Person("马云");
Sheep sheep = new Sheep("tom",1,"male", owner);//新建sheep类
Sheep sheep1 = (Sheep)sheep.clone();//克隆该类
System.out.println(sheep.hashCode() + " " + sheep.owner.hashCode());
System.out.println(sheep + " "+ sheep.owner);
System.out.println(sheep1.hashCode()+ " " + sheep1.owner.hashCode());
System.out.println(sheep1 + " " + sheep1.owner);
sheep1.owner.setName("马化腾");
System.out.println(sheep.owner);
System.out.println(sheep1.owner);
}
}
输出
1163157884 1956725890
Sheep{name='tom', age=1, sex='male', owner=Person{name='马云'}} Person{name='马云'}
356573597 1956725890
Sheep{name='tom', age=1, sex='male', owner=Person{name='马云'}} Person{name='马云'}
Person{name='马化腾'}
Person{name='马化腾'}
我们可以看出浅克隆时对象的引用仅仅是指向了原空间,而并没有复制对象。
深克隆
在深克隆中,对值类型的成员变量进行值的复制,对引用类型的成员变量也进行引用对象的复制。
自定义clone过程实现深克隆
将上面Sheep类中的clone方法改写
@Override
protected Object clone() throws CloneNotSupportedException {
Sheep sheep =null;
sheep = (Sheep)super.clone();
sheep.owner = (Person) sheep.owner.clone();//引用对象的克隆方法
return sheep;
}
测试类测试
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Person owner = new Person("马云");
Sheep sheep = new Sheep("tom",1,"male", owner);
Sheep sheep1 = (Sheep)sheep.clone();
System.out.println(sheep.hashCode() + " " + sheep.owner.hashCode());
System.out.println(sheep + " "+ sheep.owner);
System.out.println(sheep1.hashCode()+ " " + sheep1.owner.hashCode());
System.out.println(sheep1 + " " + sheep1.owner);
sheep1.owner.setName("马化腾");
System.out.println(sheep.owner);
System.out.println(sheep1.owner);
}
}
输出
1163157884 1956725890
Sheep{name='tom', age=1, sex='male', owner=Person{name='马云'}} Person{name='马云'}
356573597 1735600054
Sheep{name='tom', age=1, sex='male', owner=Person{name='马云'}} Person{name='马云'}
Person{name='马云'}
Person{name='马化腾'}
这时候我们已经实现了深克隆,但是总觉得有点“浅浅克隆”的意思,如果person类中还有对象引用那不就是。。
禁止套娃
序列化实现深克隆
两个实体类实现序列化接口
Person类
public class Person implements Serializable {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
public Person(String name){
this.name = name;
}
}
Sheep类
/**
* @author codermy
* @createTime 2020/6/16
*/
public class Sheep implements Serializable {
private String name;
private int age;
private String sex;
public Person owner;//对象引用
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 String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Person getOwner() {
return owner;
}
public void setOwner(Person owner) {
this.owner = owner;
}
public Sheep() {
}
public Sheep(String name, int age, String sex, Person owner) {
this.name = name;
this.age = age;
this.sex = sex;
this.owner = owner;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", owner=" + owner +
'}';
}
}
实现
**
* @author codermy
* @createTime 2020/7/24
*/
public class Client {
public static void main(String[] args) throws Exception {
Person owner = new Person("马云");
Sheep sheep = new Sheep("tom",1,"male", owner);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(sheep);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
Sheep sheep1 =(Sheep) ois.readObject();
bos.flush();oos.flush();
bos.close();oos.close();
ois.close();
System.out.println("Sheep: " + sheep);
System.out.println("Sheep1: " + sheep1);
System.out.println("================================");
System.out.println("Sheep: " + sheep.hashCode() + "++++++++++" + sheep.owner.hashCode());
System.out.println("Sheep1: " + sheep1.hashCode() + "++++++++++" + sheep1.owner.hashCode());
System.out.println("================================");
sheep1.owner.setName("马化腾");
System.out.println("Sheep: " + sheep.owner);
System.out.println("Sheep1: " + sheep1.owner);
}
}
输出
1163157884 1956725890
Sheep{name='tom', age=1, sex='male', owner=Person{name='马云'}} Person{name='马云'}
356573597 1735600054
Sheep{name='tom', age=1, sex='male', owner=Person{name='马云'}} Person{name='马云'}
Person{name='马云'}
Person{name='马化腾'}
原型模式的优缺点
优点:原型模式是在内存中二进制流的拷贝,要比new一个对象的性能要好,特别是需要产生大量对象时。
缺点:直接在内存中拷贝,构造函数是不会执行的。