原型模式
需求引入
有一只羊,姓名:duoli,年龄:1, 请编写程序创建和duoli属性完全一样的10只羊出来
使用传统方式
思路

代码
Sheep
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class Sheep { private String name; private int age; public Sheep() { }
public Sheep(String name, int age) { 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; } }
|
Client
1 2 3 4 5 6 7
| public class Client { public static void main(String[] args) { Sheep sheep = new Sheep("duoli",1); Sheep sheep2 = new Sheep(sheep.getName(),sheep.getAge()); Sheep sheep3 = new Sheep(sheep.getName(),sheep.getAge()); } }
|
优缺点
- 优点比较好理解,简单易操作
- 新建对象时,总是需要重新获取原始对象的属性,如果创建对象比较复杂时候,效率比较低。
- 总是需要重新初始化对象,而不是动态获取运行时的状态,不够灵活
改进思路
思路:Java中Object类是所有类的根类,Object类提供了一个clone()方法,该方法可以将一个Java对象复制一份,但是需要实现clone的Java类必须实现一个Cloneable接口,该接口标识该类能够复制且具有复制能力==》原型模式
基本介绍
- 原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象。
- 原型模式属于创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节。
- 工作原理:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建,即对象.clone();
- 原型模式中包含如下要素:
- Prototype: 原型类,声明一个克隆自己的接口。
- ConcreteProtoype:具体的圆形类,实现克隆自己的操作。
- Client:让一个克隆对象克隆自己,从而创建一个新的对象(属性一样)。
使用原型模式
思路
- sheep类实现Cloneable重写clone方法。
代码
Sheep2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| public class Sheep2 implements Cloneable{ private String name; private int age;
private Sheep friend;
public Sheep2() { }
public Sheep2(String name, int age) { 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; }
public Sheep getFriend() { return friend; }
public void setFriend(Sheep friend) { this.friend = friend; }
@Override protected Sheep2 clone() { Sheep2 sheep2 = null; try{ sheep2 = (Sheep2) super.clone(); }catch (Exception e){ e.printStackTrace(); } return sheep2; }
@Override public String toString() { return "name:"+name + "age:"+age; } }
|
Client
1 2 3 4 5 6 7 8 9 10 11
| public class Client { public static void main(String[] args) { Sheep2 sheep = new Sheep2("duoli",1); Sheep friend = new Sheep("duoli 的朋友",2); sheep.setFriend(friend); Sheep2 clone = sheep.clone(); Sheep2 clone2 = sheep.clone(); System.out.println((clone.getFriend() == clone2.getFriend())); } }
|
浅拷贝和深拷贝
“==”和 equals 方法究竟有什么区别?
==操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相等,只能用==操作符。
如果一个变量指向的数据是对象类型的,那么,这时候涉及了两块内存,对象本身占用一块内存(堆
内存),变量也占用一块内存,例如 Objet obj = new Object();变量 obj 是一个内存,内存存放的是地址引用(指向new Object开辟的内存地址),new Object()是另一个内存,此时,变量 obj 所对应的内存中存储的数值就是对象占用的那块内存的首地址。对于指向对象类型的变量,如果要比较两个变量是否指向同一个对象,即看这两个变量所对应的内存中的数值是否相等,这时候就需要用==操作符进行比较。
equals 方法是用于比较两个独立对象的内容是否相同,就好比去比较两个人的长相是否相同,它比较的两个对象是独立的。
1 2 3
| String a=new String("foo"); String b=new String("foo");
|
浅拷贝
- 对于数据类型是基础数据类型的成员变量,浅拷贝会直接进行值传递,也就是该属性值复制一份给新的对象。
- 对于数据类型是应用数据类型的成员变量,比如说成员是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向了同一个实例,这种情况下,再一个对象修改成员变量会影响到另一个对象的成员变量值。
- Object.clone()方法 是浅拷贝。
深拷贝
- 复制对象的所有基本类型的成员变量值
- 为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所有引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要多整个对象(包括对应的引用类型)进行拷贝
- 实现深拷贝方式1:重写clone方法实现深拷贝
- 实现深拷贝方式2:通过对象序列化实现深拷贝(推荐)
重写clone方法实现深拷贝
DeepCloneableTarget
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| public class DeepCloneableTarget implements Cloneable , Serializable { 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(); }
public String getCloneName() { return cloneName; }
public void setCloneName(String cloneName) { this.cloneName = cloneName; }
public String getCloneClass() { return cloneClass; }
public void setCloneClass(String cloneClass) { this.cloneClass = cloneClass; } }
|
DeepProtoType
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public class DeepProtoType implements Cloneable , Serializable { private static final long serialVersionUID = 1L; private String name; private DeepCloneableTarget deepCloneableTarget;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public DeepCloneableTarget getDeepCloneableTarget() { return deepCloneableTarget; }
public void setDeepCloneableTarget(DeepCloneableTarget deepCloneableTarget) { this.deepCloneableTarget = deepCloneableTarget; }
@Override protected DeepProtoType clone() throws CloneNotSupportedException { DeepProtoType deepProtoType = null; deepProtoType = (DeepProtoType)super.clone(); deepProtoType.deepCloneableTarget = (DeepCloneableTarget)deepProtoType.getDeepCloneableTarget().clone(); return deepProtoType; } }
|
Client
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class Client { public static void main(String[] args) { try{ DeepProtoType protoType = new DeepProtoType(); protoType.setName("A"); protoType.setDeepCloneableTarget(new DeepCloneableTarget("B","C")); DeepProtoType clone = protoType.clone(); DeepProtoType clone2 = protoType.clone(); System.out.println((clone.getDeepCloneableTarget() == clone2.getDeepCloneableTarget())); }catch (Exception e){ e.printStackTrace(); } } }
|
通过对象序列化实现深拷贝
DeepProtoType
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| public class DeepProtoType Serializable { private static final long serialVersionUID = 1L; private String name; private DeepCloneableTarget deepCloneableTarget;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public DeepCloneableTarget getDeepCloneableTarget() { return deepCloneableTarget; }
public void setDeepCloneableTarget(DeepCloneableTarget deepCloneableTarget) { this.deepCloneableTarget = deepCloneableTarget; }
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);
DeepProtoType deepProtoType = (DeepProtoType)ois.readObject(); return deepProtoType; }catch (Exception e){ e.printStackTrace(); }finally { try{ bos.close(); oos.close(); bis.close(); ois.close(); }catch (Exception e){ e.printStackTrace(); } } return null; } }
|
Client
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class Client { public static void main(String[] args) { try{ DeepProtoType protoType = new DeepProtoType(); protoType.setName("A"); protoType.setDeepCloneableTarget(new DeepCloneableTarget("B","C")); DeepProtoType clone = (DeepProtoType)protoType.deepClone(); DeepProtoType clone2 = (DeepProtoType)protoType.deepClone(); System.out.println((clone.getDeepCloneableTarget() == clone2.getDeepCloneableTarget())); }catch (Exception e){ e.printStackTrace(); } } }
|