原型模式
1. 什么是原型模式:
用原型实例指定创建对象种类,并且通过拷贝这些原型创建新的对象。是一种创建型设计模式,允许一个对象再创建另外一个可定制对象,无需知道创建的细节。
2.为什么要用原型模式:
复制类时可以简单操作,而无需在代码中直接冗余的创建,让程序有更高的效率和扩展性。
3.原型模式适用于什么地方:
- 当一个系统应该独立于他的产品创建,构成和表示时。
- 要实例化的类是在运行时指定
- 为了避免一个与产品类层次平行的工厂类层次时
- 当一个类实例只能有几个不同状态组合的一种时。
**原型模式实现方法:**在类中实现clone方法,给使用者提供clone接口。
一、浅拷贝复制:
- 对于数据类型为基本数据类型,浅拷贝会直接进行值传递,就是将该属性值复制给新的对象。
- 对于引用数据类型,浅拷贝会进行引用传递,也就是将该对象的引用值赋给新的对象,则新对象与被拷贝的对象的成员变量都指向一个实例,对原被拷贝的变量实例的值的改变也会影响新对象中的变量。
实现:
- 实现Cloneable接口,重写clone方法。
原型类:
class DoriSheep implements Cloneable {
private String name ;
private int age ;
public DoriSheep sheep;
@Override
protected Object clone() throws CloneNotSupportedException {
DoriSheep sheep =null;
try {
sheep = (DoriSheep) super.clone();
}catch (Exception e){
System.out.println("chucuole ");
}
return sheep;
}
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 DoriSheep getSheep() {
return sheep;
}
public void setSheep(DoriSheep sheep) {
this.sheep = sheep;
}
@Override
public String toString() {
return "DoriSheep{" +
"name='" + name + '\'' +
", age=" + age +
", sheep=" + sheep +
'}';
}
}
测试类:
public class PrototypeFirstTest {
public static void main(String[] args) {
DoriSheep sheep = new DoriSheep();
sheep.setName("Dori");
sheep.setAge(20);
DoriSheep Fieldsheep = new DoriSheep();
sheep.setSheep(Fieldsheep);
try {
DoriSheep sheep1 = (DoriSheep) sheep.clone();
DoriSheep sheep2 = (DoriSheep) sheep.clone();
System.out.println(sheep +" "+sheep.sheep.hashCode());
System.out.println(sheep1 +" "+sheep1.sheep.hashCode());
System.out.println(sheep2 +" "+sheep2.sheep.hashCode());
System.out.println("sheep1.sheep==sheep.sheep:"+ (sheep1.sheep==sheep.sheep) );
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
输出:
结论:浅拷贝后的对象与被拷贝的对象所得到引用变量是同一个实例。
二、深拷贝复制:
目的:使得拷贝后的对象与被拷贝的对象的引用变量不是用一个实例
1、重写克隆方法时指定引用变量类型不同。
class DoriSheep implements Cloneable, Serializable {
private String name ;
private int age ;
public Sheep sheep;
@Override
protected Object clone() throws CloneNotSupportedException {
DoriSheep newsheep =null;
try {
newsheep = (DoriSheep) super.clone();
newsheep.sheep = (Sheep) sheep.clone();
}catch (Exception e){
System.out.println("chucuole ");
}
return newsheep;
}
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 "DoriSheep{" +
"name='" + name + '\'' +
", age=" + age +
", sheep=" + sheep +
'}';
}
}
2、通过输入输出流实现
class DoriSheep implements Cloneable, Serializable {
private String name ;
private int age ;
public Sheep sheep;
@Override
protected Object clone() throws CloneNotSupportedException {
DoriSheep newsheep =null;
try {
newsheep = (DoriSheep) super.clone();
newsheep.sheep = (Sheep) sheep.clone();
}catch (Exception e){
System.out.println("chucuole ");
}
return newsheep;
}
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 "DoriSheep{" +
"name='" + name + '\'' +
", age=" + age +
", sheep=" + sheep +
'}';
}
//深拷贝
public Object deepClone(){
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
DoriSheep doriSheep = null;
try{
//序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
doriSheep= (DoriSheep) ois.readObject();
return doriSheep;
}
catch (Exception e){
e.printStackTrace();
}finally {
try {
bos.close();
oos.close();
bis.close();
ois.close();
}catch (Exception e){
e.printStackTrace();
}
}
return doriSheep;
}
}
推荐用第二种,因为第一种每个引用数据类型都要实现对实例的复制,而第二种是写了一个deepclone()方法,利用输入输出流来实现,要在拷贝类中实现Serializable接口。
原型模式缺点:
- 需要为每个类都配备一个克隆方法,对新类来说也许不难,但对已有的类进行改造时,需要修改其源码,这违反了设计模式中的ocp原则。