1. 克隆羊问题
克隆三个一模一样的羊, 代码如下:
package com.liyang;
public class Sheep {
private String name;
private int age;
private String color;
public Sheep() {
super();
}
public Sheep(String name, int age, String color) {
super();
this.name = name;
this.age = age;
this.color = color;
}
@Override
public String toString() {
return "Sheep [name=" + name + ", age=" + age + ", color=" + color + "]";
}
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 getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
package com.liyang;
public class Client {
public static void main(String[] args) {
Sheep sheep = new Sheep("tom", 1, "白色");
Sheep sheep2 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
Sheep sheep3 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
System.out.println(sheep);
System.out.println(sheep2);
System.out.println(sheep3);
}
}
优点: 容易理解, 简单易操作
缺点: 创建对象时, 总是需要获取原始对象的属性, 如果创建对象比较复杂则效率低
总是需要重新初始化对象, 而不是动态获取对象运行时状态, 不够灵活
改进: Object类中有一个clone()的方法, 该方法可以将Java对象复制一份, 但是需要Java类必须实现一个接口Cloneable, 该接口表示该类能够复制并有复制能力 => 原型模式
2. 基本介绍
- 原型模式是指: 用原型实例指定创建对象的种类, 并且通过拷贝这些原型创在新的对象
- 原型模式是一种创建型设计模式, 允许一个对象可创建另一个可定制的对象, 无需知道细节
- 工作原理: 通过将一个原型对象传给那个要发动创建的对象, 这个要发动创建的对象通过请求原型对象拷贝他们自己来实施创建 即对象.clone()
- 孙悟空拔出猴毛, 变出其他的孙悟空…
客户(Client)角色:客户类提出创建对象的请求;
抽象原型(Prototype)角色:这是一个抽象角色,通常由一个Java接口或者Java抽象类实现。此角色定义了的具体原型类所需的实现的方法。
具体原型(Concrete Prototype)角色:此角色需要实现抽象原型角色要求的克隆相关的接口。
package com.liyang;
public class Sheep implements Cloneable {
private String name;
private int age;
private String color;
public Sheep() {
super();
}
public Sheep(String name, int age, String color) {
super();
this.name = name;
this.age = age;
this.color = color;
}
@Override
public String toString() {
return "Sheep [name=" + name + ", age=" + age + ", color=" + color + "]";
}
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 getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Sheep sheep = null;
sheep = (Sheep)super.clone();
return sheep;
}
}
package com.liyang;
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Sheep sheep = new Sheep("tom", 1, "白色");
Sheep sheep2 = (Sheep)sheep.clone();
System.out.println(sheep);
System.out.println(sheep2);
}
}
这样子使用原型模式, 一旦我们的Sheep类增加或者减少了属性, 我们不需要做任何变化…
3. 浅拷贝和深拷贝
3.1 浅拷贝
- 对于数据类型是进本数据类型的成员变量, 浅拷贝会直接进行值传递, 也就是将属性值复制一份给新的对象
- 对于数据类型是引用数据类型的成员变量, 比如说是数组 类的对象, 那么浅拷贝就会进行引用传递, 也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象. 这样子实际上他们两个是指向同一个实例, 那么我们一旦修改其中一个, 另外一个也会跟着发生变化…
- 默认的clone方法是浅拷贝
3.2 深拷贝
- 复制所有基本数据类型
- 为对象的引用数据类型申请存储空间, 并复制, 直到该对象可达所有的对象
- 重写clone方法实现深拷贝
- 通过对象序列化实现深拷贝
3.2.1 方式一 (Cloneable接口实现)
package com.liyang;
public class SheepTarget implements Cloneable {
private String name;
private int age;
public SheepTarget() {
super();
}
public SheepTarget(String name, int age) {
super();
this.name = name;
this.age = 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 "SheepTarget [name=" + name + ", age=" + age + "]";
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
package com.liyang;
public class Sheep implements Cloneable {
private String name;
private int age;
private String color;
public SheepTarget friends;
public SheepTarget getFriends() {
return friends;
}
public void setFriends(SheepTarget friends) {
this.friends = friends;
}
public Sheep() {
super();
}
public Sheep(String name, int age, String color) {
super();
this.name = name;
this.age = age;
this.color = color;
}
@Override
public String toString() {
return "Sheep [name=" + name + ", age=" + age + ", color=" + color + ", friends=" + friends + "]";
}
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 getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Object object = null;
// 拷贝基本数据类型
object = super.clone();
// 拷贝引用
Sheep sheep = (Sheep) object;
sheep.friends = (SheepTarget) friends.clone();
return sheep;
}
}
package com.liyang;
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Sheep sheep = new Sheep("tom", 1, "白色");
sheep.setFriends(new SheepTarget("aa", 1));
Sheep sheep2 = (Sheep) sheep.clone();
System.out.println(sheep.friends.hashCode());
System.out.println(sheep2.friends.hashCode());
}
}
3.2.2 方式二 (通过对象序列化实现)
package com.liyang;
import java.io.Serializable;
public class SheepTarget implements Serializable{
private String name;
private int age;
public SheepTarget() {
super();
}
public SheepTarget(String name, int age) {
super();
this.name = name;
this.age = 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 "SheepTarget [name=" + name + ", age=" + age + "]";
}
}
package com.liyang;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Sheep implements Serializable {
private String name;
private int age;
private String color;
public SheepTarget friends;
public SheepTarget getFriends() {
return friends;
}
public void setFriends(SheepTarget friends) {
this.friends = friends;
}
public Sheep() {
super();
}
public Sheep(String name, int age, String color) {
super();
this.name = name;
this.age = age;
this.color = color;
}
@Override
public String toString() {
return "Sheep [name=" + name + ", age=" + age + ", color=" + color + ", friends=" + friends + "]";
}
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 getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public Object deepClone() {
// 创建流
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);
Sheep sheep = (Sheep)ois.readObject();
return sheep;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
try {
// 关闭流
bos.close();
oos.close();
bis.close();
ois.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
package com.liyang;
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Sheep sheep = new Sheep("tom", 1, "白色");
sheep.setFriends(new SheepTarget("aa", 1));
Sheep sheep2 = (Sheep)sheep.deepClone();
System.out.println(sheep.friends.hashCode());
System.out.println(sheep2.friends.hashCode());
}
}
4. 注意事项
- 创建对象比较复杂, 可以利用原型模式来简化创建过程, 同时能提高效率
- 不用重新初始化对象, 而是动态获取对象运行时的状态
- 如果原始对象发生变化(增加或者减少属性), 其他的克隆对象也会发生相应的变化, 无需修改代码
- 实现深拷贝需要比较复杂代码
- 缺点: 每个类需要一个clone方法, 这样对已有的类进行改造违背了ocp原则