原型模式
用原型对象,拷贝,创建新的对象。
就是复制。咦惹。
拷贝出的对象只是属性相同,对象可不是同一个对象,这点很容易理解。
原型模式的优点是在对象属性增加或减少时方便
案例:克隆羊
现在有一只羊,名为tom,年龄为1岁,颜色为白色。请根据Tom属性编写程序创建与根据Tom属性完全相同的10只羊。
思考:羊类class Sheep属性name age color
public class Test {
public static void main(String[] args) {
//一般方法
Sheep sheep=new Sheep("tom",1,"白色");
new Sheep(sheep.getName(),sheep.getAge(),sheep.getColor());
new Sheep(sheep.getName(),sheep.getAge(),sheep.getColor());
new Sheep(sheep.getName(),sheep.getAge(),sheep.getColor());
new Sheep(sheep.getName(),sheep.getAge(),sheep.getColor());
new Sheep(sheep.getName(),sheep.getAge(),sheep.getColor());
new Sheep(sheep.getName(),sheep.getAge(),sheep.getColor());
new Sheep(sheep.getName(),sheep.getAge(),sheep.getColor());
new Sheep(sheep.getName(),sheep.getAge(),sheep.getColor());
new Sheep(sheep.getName(),sheep.getAge(),sheep.getColor());
new Sheep(sheep.getName(),sheep.getAge(),sheep.getColor());//烦
}
}
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;
}
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
public String toString() {
return "Sheep [name=" + name + ", age=" + age + ", color=" + color + "]";
}
}
原型模式的核心操作
Java中Object类中提供了clone方法,该方法可以将一个对象复制一份,但是该对象的类得实现接口Cloneable。默认为浅拷贝
使用原型模式进行操作
public class Test1 {
public static void main(String[] args) throws CloneNotSupportedException {
Sheep sheep=new Sheep("tom",1,"白色");
Sheep sheep1=(Sheep) sheep.clone();
Sheep sheep2=(Sheep)sheep.clone();
Sheep sheep3=(Sheep)sheep.clone();
Sheep sheep4=(Sheep)sheep.clone();
Sheep sheep5=(Sheep)sheep.clone();
Sheep sheep6=(Sheep)sheep.clone();
Sheep sheep7=(Sheep)sheep.clone();
Sheep sheep8=(Sheep)sheep.clone();
Sheep sheep9=(Sheep)sheep.clone();
Sheep sheep10=(Sheep)sheep.clone();//实际上还是烦的,不懂原型模式的意义在哪。据说有更高的效率。
System.out.println(sheep);
System.out.println(sheep1);
System.out.println(sheep2);
System.out.println(sheep3);
System.out.println(sheep4);
System.out.println(sheep5);
System.out.println(sheep6);
System.out.println(sheep7);
System.out.println(sheep8);
System.out.println(sheep9);
System.out.println(sheep10);
}
}
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;
}
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
public String toString() {
return "Sheep [name=" + name + ", age=" + age + ", color=" + color + "]";
}
//重写Cloneable中的clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
Sheep sheep=null;
sheep=(Sheep) super.clone();
return sheep;
}
}
Spring中的bean的创建,就使用了原型模式。
原型模式中的浅拷贝
羊中有属性a,这个属性a有指针指向B对象
克隆羊属性a,这个属性a的有的指针也指向B对象
经测试不同sheep的friend的地址值相同且属性相同,说明为同一个friend。
即不同羊的friend为同一个friend
这里的对象是排除基本数据类型和字符串数据类型的
public class Test2 {
public static void main(String[] args) throws CloneNotSupportedException {
Sheep sheep=new Sheep("tom",1,"白色");
sheep.friend=new Sheep("jack",2,"黑色");
Sheep sheep1=(Sheep) sheep.clone();
Sheep sheep2=(Sheep)sheep.clone();
Sheep sheep3=(Sheep)sheep.clone();
System.out.println("sheep="+sheep+"sheep.frend="+sheep.friend.hashCode());
System.out.println("sheep1="+sheep1+"sheep1.frend="+sheep1.friend.hashCode());
System.out.println("sheep2="+sheep2+"sheep2.frend="+sheep2.friend.hashCode());
System.out.println("sheep3="+sheep3+"sheep3.frend="+sheep3.friend.hashCode());
/*
* 结果: sheep=Sheep [name=tom, age=1, color=白色]sheep.frend=366712642
sheep1=Sheep [name=tom, age=1, color=白色]sheep1.frend=366712642
sheep2=Sheep [name=tom, age=1, color=白色]sheep2.frend=366712642
sheep3=Sheep [name=tom, age=1, color=白色]sheep3.frend=366712642
把它们的friend地址值打出来如下,是相同的。
test2.Sheep@6d06d69c
test2.Sheep@6d06d69c
test2.Sheep@6d06d69c
test2.Sheep@6d06d69c
*/
//也就是说Sheep中的属性friend对象,在其他克隆羊中friend都是同一对象,称此为浅拷贝。
//这里的friend就类似于它的指针被克隆羊复制了,所有指针指向同一对象。
}
}
class Sheep implements Cloneable{
private String name;
private int age;
private String color;
public Sheep friend;//friend是对象。
public Sheep() {
super();
}
public Sheep(String name, int age, String color) {
super();
this.name = name;
this.age = age;
this.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
public String toString() {
return "Sheep [name=" + name + ", age=" + age + ", color=" + color + "]";
}
//重写Cloneable中的clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
Sheep sheep=null;
sheep=(Sheep) super.clone();
return sheep;
}
}
原型模式中的深拷贝
羊中有属性a,这个属性a有指针指向B对象
克隆羊属性a,这个属性a的有的指针指向B对象的克隆
经测试不同sheep的friend的地址值不同但属性相同,说明不是同一个friend。
即不同羊的friend为不同的friend
这里的对象是排除基本数据类型和字符串数据类型的
对此案例深拷贝,用静态方法
public class Test3 {
public static void main(String[] args) throws CloneNotSupportedException {
Sheep sheep=new Sheep("tom",1,"白色");
sheep.friend=new Sheep("jack",2,"黑色");
Sheep sheep1=Sheep.friendClone((Sheep)sheep.clone());
Sheep sheep2=Sheep.friendClone((Sheep)sheep.clone());
Sheep sheep3=Sheep.friendClone((Sheep)sheep.clone());
System.out.println("sheep="+sheep+"sheep.frend="+sheep.friend.hashCode());
System.out.println("sheep1="+sheep1+"sheep1.frend="+sheep1.friend.hashCode());
System.out.println("sheep2="+sheep2+"sheep2.frend="+sheep2.friend.hashCode());
System.out.println("sheep3="+sheep3+"sheep3.frend="+sheep3.friend.hashCode());
System.out.println(sheep.friend);//fiend 中的属性还是相同的
System.out.println(sheep1.friend);
System.out.println(sheep2.friend);
System.out.println(sheep3.friend);
System.out.println(sheep1.friend.friend);
/*结果(此结果为测试结果而非固定代码结果)
* Sheep的friend属性 [name=jack, age=2, color=黑色]
Sheep1的friend属性[name=jack, age=2, color=黑色]
Sheep2的friend属性 [name=jack, age=2, color=黑色]
Sheep3的friend属性 [name=jack, age=2, color=黑色]
* sheep=test3.Sheep@15db9742sheep.frend=1829164700
* sheep1=test3.Sheep@7852e922sheep1.frend=1311053135
* sheep2=test3.Sheep@70dea4esheep2.frend=1550089733
* sheep3=test3.Sheep@33909752sheep3.frend=1442407170
* test3.Sheep@6d06d69c sheep的friend的地址
* test3.Sheep@4e25154f sheep1的friend的地址
* test3.Sheep@5c647e05 sheep2的friend的地址
* test3.Sheep@55f96302 sheep3的sheep的friend的地址
* null sheep1.friend.friend的地址值
*
* 说明不同sheep的friend的属性相同但地址值不同,即friend对象不是同一个。
*/
}
}
class Sheep implements Cloneable{
private String name;
private int age;
private String color;
public Sheep friend;//friend是对象。
public Sheep() {
super();
}
public Sheep(String name, int age, String color) {
super();
this.name = name;
this.age = age;
this.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
public String toString() {
return "Sheep [name=" + name + ", age=" + age + ", color=" + color + "]";
}
//重写Cloneable中的clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
Sheep sheep=null;
sheep=(Sheep) super.clone();
return sheep;
}
public static Sheep friendClone(Sheep sheep) throws CloneNotSupportedException {
sheep.friend=(Sheep) sheep.friend.clone();
return sheep;
}
}
深拷贝的实现方式一:重写clone方法
此方式思路与上面的静态思路相同
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
DeepProtoType deepProtoType=new DeepProtoType();
deepProtoType.name="宋江";
deepProtoType.deepCloneableTarget=new DeepCloneableTarget("大牛", "大牛的类");
//深拷贝
DeepProtoType deepProtoType2=(DeepProtoType) deepProtoType.clone();
System.out.println(deepProtoType);
System.out.println(deepProtoType2);
/*
* DeepProtoType [name=宋江,deepCloneableTarget=test.DeepCloneableTarget@15db9742]
* DeepProtoType[name=宋江, deepCloneableTarget=test.DeepCloneableTarget@6d06d69c]
*
*/
System.out.println(deepProtoType.deepCloneableTarget);
System.out.println(deepProtoType2.deepCloneableTarget);
// DeepCloneableTarget [cloneName=大牛, cloneClass=大牛的类]
// DeepCloneableTarget [cloneName=大牛, cloneClass=大牛的类]
}
}
//实现Serializable,Cloneable接口
class DeepCloneableTarget implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;// 这个是啥?
private String cloneName;
private String cloneClass;
public DeepCloneableTarget(String cloneName, String cloneClass) {
this.cloneName = cloneName;
this.cloneClass = cloneClass;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "DeepCloneableTarget [cloneName=" + cloneName + ", cloneClass=" + cloneClass + "]";
}
}
class DeepProtoType implements Serializable, Cloneable {
public String name;
public DeepCloneableTarget deepCloneableTarget;
public DeepProtoType() {
}
// 完成深拷贝实现,重写clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
Object deep = null;
// 这里完成对基本数据类型和String类型的复制
deep = super.clone();
// 这里对剩余类型进行处理
DeepProtoType deepProtoType = (DeepProtoType) deep;
deepProtoType.deepCloneableTarget = (DeepCloneableTarget) deepCloneableTarget.clone();
return deepProtoType;
}
@Override
public String toString() {
return "DeepProtoType [name=" + name + ", deepCloneableTarget=" + deepCloneableTarget + "]";
}
}
深拷贝的实现方式二:通过对象序列化(推荐)
public class Test1 {
public static void main(String[] args) throws CloneNotSupportedException, ClassNotFoundException {
DeepProtoType deepProtoType=new DeepProtoType();
deepProtoType.name="宋江";
deepProtoType.deepCloneableTarget=new DeepCloneableTarget("大牛", "大牛的类");
DeepProtoType deepProtoType2=(DeepProtoType) deepProtoType.deepClone();
System.out.println(deepProtoType);
System.out.println(deepProtoType2);
// DeepProtoType [name=宋江, deepCloneableTarget=test1.DeepCloneableTarget@3d4eac69]
// DeepProtoType [name=宋江, deepCloneableTarget=test1.DeepCloneableTarget@214c265e]
System.out.println(deepProtoType.deepCloneableTarget);
System.out.println(deepProtoType2.deepCloneableTarget);
// DeepCloneableTarget [cloneName=大牛, cloneClass=大牛的类]
// DeepCloneableTarget [cloneName=大牛, cloneClass=大牛的类]
}
}
//实现Serializable,Cloneable接口
class DeepCloneableTarget implements Serializable, Cloneable {
private static final long serialVersionUID = 1L;// 这个是啥?
private String cloneName;
private String cloneClass;
public DeepCloneableTarget(String cloneName, String cloneClass) {
this.cloneName = cloneName;
this.cloneClass = cloneClass;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "DeepCloneableTarget [cloneName=" + cloneName + ", cloneClass=" + cloneClass + "]";
}
}
class DeepProtoType implements Serializable, Cloneable {
public String name;
public DeepCloneableTarget deepCloneableTarget;
public DeepProtoType() {
}
@Override
public String toString() {
return "DeepProtoType [name=" + name + ", deepCloneableTarget=" + deepCloneableTarget + "]";
}
// 序列化核心
public Object deepClone() throws ClassNotFoundException {
// 创建流对象
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);
DeepProtoType copyObj=(DeepProtoType) ois.readObject();
return copyObj;
} catch (IOException e) {
e.printStackTrace();
return null;
}finally {
//关闭流
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}