实例探索Java模式之路——原始模型

原始模型


1、原始模型模式属于对象的创建模式。通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个对象的方法创建出更多同类型的对象。


2、Java语言的构件模型直接支持原型模型模式。所有的javabean都继承自java.lang.object,object类提供一个clone()方法,可以将一个javabean对象复制一份。
这个javabean必须实现一个标识接口cloneable,这表明javabean支持复制。

3、Java所有的类都是从java.lang.object类继承,而object类提供clone方法对对象进行复制。
子类可以把这个方法置换,提供自己需要的复制方法。

4、一个克隆的例子:


public class treeClone implements Cloneable {

private int height, age, weight;

// 构造方法
public treeClone(int height, int weight) {
super();
this.height = height;
this.age = 0;
this.weight = weight;
}


public int getAge() {
return age;
}


public void setAge(int age) {
this.age = age;
}


public int getHeight() {
return height;
}


public int getWeight() {
return weight;
}


// 克隆方法
public Object clone() {


// 创建一个本类的对象,并返还给调用者


treeClone tempClone = new treeClone(height, weight);
tempClone.setAge(age);


// 返还类型要是Object


return (Object) tempClone;
}
}


//客户端


public class client {


private static treeClone thisTree, thatTree;

public static void main(String[] args) {


// 先创建treeClone的实例
thisTree = new treeClone(150, 100);

thisTree.setAge(50);


// 将此对象复制一份
thatTree = (treeClone) thisTree.clone();

System.out.println("thistree age is" + thisTree.getAge());
System.out.println("thistree Hegiht is" + thisTree.getHeight());
System.out.println("thistree weight is" + thisTree.getWeight());

// 克隆得到的对象
System.out.println("thatTree age is" + thatTree.getAge());
System.out.println("thatTree Hegiht is" + thatTree.getHeight());
System.out.println("thatTree weight is" + thatTree.getWeight());
}


}


结果打印
thistree age is50
thistree Hegiht is150
thistree weight is100
thatTree age is50
thatTree Hegiht is150
thatTree weight is100


通过结果我们得到,克隆对象与原对象性质完全一样。
client对象持有对treeClone对象的引用,然后client对象调用thatTree = (treeClone) thisTree.clone(),得到复制后的对象。
这就是原始模型模式。


5、克隆满足条件:克隆方法将对象复制一份并返还给调用者。
1、对任何对象X,都有x.clone!=x。克隆对象与原对象不是同一个对象。
2、对于任何对象x.都有x.clone().getClass==x.getClass().克隆对象与原对象的类型一样。
3、对象x的equals()方法定义恰当,x.clone().equals(x)应当成立。


6、原型模型模式结构(分为:简单形式和登记形式)

1、简单形式结构:

实例探索Java模式之路——原始模型


客户(client):提出创建对象请求
抽象原型(Clonable):给出所有的的具体原型类所需的接口。
具体原型(ConcretePrototype):被复制的对象。


简单形式例子:


//抽象原型
public interface abstractPrototype extends Cloneable {
Object clone();
}


//具体原型
public class concretePrototype implements abstractPrototype {


private int height, age, weight;


// 构造方法
public concretePrototype(int height, int weight) {
super();
this.height = height;
this.age = 0;
this.weight = weight;
}


public int getAge() {
return age;
}


public void setAge(int age) {
this.age = age;
}


public int getHeight() {
return height;
}


public int getWeight() {
return weight;
}


// 实现克隆方法
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
return null;
}


}


}


//客户端
public class client {


private static concretePrototype abstractprototype, otherabstractprototype;


public static void main(String[] args) {
// 先创建concretePrototype的实例


abstractprototype = new concretePrototype(20, 50);


otherabstractprototype = (concretePrototype) abstractprototype.clone();


System.out.println(abstractprototype.getHeight());
System.out.println(abstractprototype.getWeight());
System.out.println(abstractprototype.getClass());
// 克隆得到的对象
System.out.println("复制的对象");
System.out.println(otherabstractprototype.getHeight());
System.out.println(otherabstractprototype.getWeight());
System.out.println(otherabstractprototype.getClass());
}


}


结果打印:
20
50
class simplemodel.concretePrototype
复制的对象
20
50
class simplemodel.concretePrototype




2、登记形式:

实例探索Java模式之路——原始模型
客户:向管理员提出创建对象请求。
抽象原型:给出所有的的具体原型类所需的接口。
具体原型:被复制的对象。
原型管理器:创建具体原型类的对象,并记录每一个被创建的对象。




//抽象原型
public interface abstractPrototype extends Cloneable {
public Object clone();
}


package registerModel;


//具体原型
public class concretePrototype implements abstractPrototype {


private int height, age, weight;


// 构造方法
public concretePrototype(int height, int weight) {
super();
this.height = height;
this.age = 0;
this.weight = weight;
}


public concretePrototype() {
super();
}


public int getAge() {
return age;
}


public void setAge(int age) {
this.age = age;
}


public int getHeight() {
return height;
}


public int getWeight() {
return weight;
}


// 实现克隆方法
public synchronized Object clone() {
abstractPrototype temp = null;
try {
temp = (abstractPrototype) super.clone();


return temp;
} catch (CloneNotSupportedException e) {
System.out.println("clone error!");
} finally {
return temp;
}


}


}




import java.util.Vector;


/**
* 原型管理器角色保持一个聚集,作为对所有原型对象的登记,这个角色提供必要的 方法,
* 供外界增加新的原型对象和取得已经登记过的原型对象。
*/
public class prototypemanager {


private Vector objects = new Vector();


// 聚集管理方法:增加一个新的对象
public void add(abstractPrototype object) {
objects.add(object);
}


// 聚集管理方法:取出聚集中的一个对象
public abstractPrototype get(int i) {
return (abstractPrototype) objects.get(i);
}


// 聚集管理方法:给出聚集大小
public int getSize() {
return objects.size();
}
}


package registerModel;


//客户端
public class client {


// 要得到管理器的实例
private prototypemanager mgr = new prototypemanager();
private concretePrototype prototype;


public void registerPrototype() {
prototype = new concretePrototype(15, 50);


abstractPrototype copytype1 = (abstractPrototype) prototype.clone();
abstractPrototype copytype2 = (abstractPrototype) prototype.clone();


mgr.add(copytype1);
mgr.add(copytype2);
mgr.getSize();


System.out.println(mgr.getSize());
System.out.println(mgr.get(1));


if (prototype != copytype1) {
System.out.println("克隆对象与原对象不是同一个对象");
}
if (copytype2 != copytype1) {
System.out.println("克隆对象1与克隆对象2不是同一个对象");
}
if (prototype != copytype2) {
System.out.println("克隆对象2与原对象不是同一个对象");
}
}


public static void main(String[] args) {


client c = new client();


c.registerPrototype();


}
}


两种形式区别:


如果需要创建的原型对象数目较少而且比较固定的话,采用第一种,这时原型对象的引用可以由客户端自己保存。


如果创建的原型对象数目不固定,采用第二种,客户端不保存对原型对象的引用,这个任务被交给管理员对象,在复制一个原型对象之前,客户端可以查看管理员对象是否存在一个满足要求的原型对象。如果存在,可以直接从管理员类取得这个对象的引用,如果没有,客户端就需要自行复制此原型对象。




7、模式的实现:深复制和浅复制


1、浅复制:


被复制的对象的所有的变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。


import java.util.Date;


//具体原型
public class Monkey implements Cloneable {


private int height;
private int weight;
private GoldStaff staff =new GoldStaff();// 持有金箍棒的实例
private Date birthDate;


// 无参构造
public Monkey() {
System.out.println("具体原形的无参构造");
this.birthDate = new Date();
}


// 克隆方法
@Override
protected Object clone() {
Monkey temp = null;


try {
temp = (Monkey) super.clone();
} catch (CloneNotSupportedException e) {
System.out.println("克隆失败!");
} finally {
return temp;
}
}


public int getHeight() {
return height;
}


public void setHeight(int height) {
this.height = height;
}


public int getWeight() {
return weight;
}


public void setWeight(int weight) {
this.weight = weight;
}


public Date getBirthDate() {
return birthDate;
}


public void setBirthDate(Date birthDate) {
this.birthDate = birthDate;
}


public GoldStaff getStaff() {
return staff;
}


public void setStaff(GoldStaff staff) {
this.staff = staff;
}


}




//金箍棒类


public class GoldStaff {
// 长度
private float height = 100.0F;
// 粗细
private float diameter = 10.0F;


// 无参构造
public GoldStaff() {
System.out.println("金箍棒的无参构造");
}


// 每次调用此方法,长度和半径都增加一倍
public void grow() {
this.diameter *= 2.0;
this.height *= 2;
}


// 每次调用此方法,长度和半径都减小一倍
public void shrink() {
this.diameter /= 2.0;
this.height /= 2;
}


// 移动方法
public void move() {
System.out.println("金箍棒的移动方法");
}


public float getHeight() {
return height;
}


public void setHeight(float height) {
this.height = height;
}


public float getDiameter() {
return diameter;
}


public void setDiameter(float diameter) {
this.diameter = diameter;
}


}



//客户端
public class TheGreatestSageclient {


// 持有具体原型的实例
private Monkey monkey = new Monkey();


public void change() {
// 创建大圣本尊对象
Monkey copyMonkey;


// 空循环,创建分身
for (int i = 0; i < 1000; i++) {
}


copyMonkey = (Monkey) monkey.clone();


copyMonkey.getStaff().grow();// 调用变大方法,复制猴子的金箍棒变大了


monkey.getStaff().shrink();// 猴王调用缩小方法,猴王金箍棒变小


System.out.println("猴王生日" + monkey.getBirthDate());


System.out.println("复制猴王生日" + copyMonkey.getBirthDate());


System.out.println("猴王==复制猴王?" + (copyMonkey == monkey));


/*
* 持有的是同一个金箍棒的。 浅复制被复制的对象的所有的变量都含有与原来的对象相同的值, 而所有的对其他对象的引用都仍然指向原来的对象。
* 浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
*/
System.out.println("猴王金箍棒==复制猴王金箍棒?"
+ (copyMonkey.getStaff() == monkey.getStaff()));


// 长度一样,说明操作是同一个对象。
System.out.println("猴王的金箍棒长度" + monkey.getStaff().getHeight());
System.out.println("复制猴王的金箍棒长度" + copyMonkey.getStaff().getHeight());
}


public static void main(String[] args) {
TheGreatestSageclient sageMonkey = new TheGreatestSageclient();
sageMonkey.change();
}
}




结果打印;
金箍棒的无参构造
具体原形的无参构造
猴王生日Tue May 23 16:30:05 GMT+08:00 2017
复制猴王生日Tue May 23 16:30:05 GMT+08:00 2017
猴王==复制猴王?false
猴王金箍棒==复制猴王金箍棒?true
猴王的金箍棒长度100.0
复制猴王的金箍棒长度100.0


复制对象与本尊不相等,二者时克隆关系,复制对象与本尊持有的金箍棒引用全部指向同一个对象,所有的猴子使用一个金箍棒。要想实现每个猴子都有一个金箍棒,就要使用深复制。


2、深复制:


实现深复制,所有的复制对象都实现Java.io.Serializable接口。
被复制的对象的所有的变量都含有与原来的对象相同的值,所有的对其他对象的引用也都复制了一遍。深复制不仅复制所考虑的对象,而且复制它所引用的对象。


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OptionalDataException;
import java.io.Serializable;
import java.util.Date;


//具体原型
public class Monkey implements Cloneable, Serializable {


private int height;
private int weight;
private GoldStaff staff;// 持有金箍棒的实例
private Date birthDate;


// 无参构造
public Monkey() {
System.out.println("具体原形的无参构造");
this.birthDate = new Date();
this.staff = new GoldStaff();// 得到金箍棒的实例
}


// 深克隆方法


public Object deepclone() throws IOException, OptionalDataException,
ClassNotFoundException {


// 将对象写到流里


ByteArrayOutputStream bo = new ByteArrayOutputStream();


ObjectOutputStream oo = new ObjectOutputStream(bo);


oo.writeObject(this);


// 将对象从流里读出来


ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());


ObjectInputStream oi = new ObjectInputStream(bi);


return (oi.readObject());


}


// 浅克隆
@Override
protected Object clone() {
Monkey temp = null;


try {
temp = (Monkey) super.clone();
} catch (CloneNotSupportedException e) {
System.out.println("克隆失败!");
} finally {
return temp;
}
}


public int getHeight() {
return height;
}


public void setHeight(int height) {
this.height = height;
}


public int getWeight() {
return weight;
}


public void setWeight(int weight) {
this.weight = weight;
}


public Date getBirthDate() {
return birthDate;
}


public void setBirthDate(Date birthDate) {
this.birthDate = birthDate;
}


public GoldStaff getStaff() {
return staff;
}


public void setStaff(GoldStaff staff) {
this.staff = staff;
}


}


//金箍棒类


import java.io.Serializable;


public class GoldStaff implements Cloneable, Serializable {
// 长度
private float height = 100.0F;
// 粗细
private float diameter = 10.0F;


// 无参构造
public GoldStaff() {
System.out.println("金箍棒的无参构造");
}


// 每次调用此方法,长度和半径都增加一倍
public void grow() {
this.diameter *= 2.0;
this.height *= 2;
}


// 每次调用此方法,长度和半径都减小一倍
public void shrink() {
this.diameter /= 2.0;
this.height /= 2;
}


// 移动方法
public void move() {
System.out.println("金箍棒的移动方法");
}


public float getHeight() {
return height;
}


public void setHeight(float height) {
this.height = height;
}


public float getDiameter() {
return diameter;
}


public void setDiameter(float diameter) {
this.diameter = diameter;
}


}




import java.io.IOException;


//客户端
public class TheGreatestSageclient {


// 持有具体原型的实例
private Monkey monkey = new Monkey();


public void change() throws IOException, ClassNotFoundException {
// 创建大圣本尊对象
Monkey copyMonkey;


// 空循环,创建分身
for (int i = 0; i < 1000; i++) {
}


copyMonkey = (Monkey) monkey.deepclone();// 采用深克隆


copyMonkey.getStaff().grow();// 调用变大方法,复制猴子的金箍棒变大了


monkey.getStaff().shrink();// 猴王调用缩小方法,猴王金箍棒变小

copyMonkey.getStaff().move();//猴王调用移动方法


System.out.println("猴王生日" + monkey.getBirthDate());


System.out.println("复制猴王生日" + copyMonkey.getBirthDate());


System.out.println("猴王==复制猴王?" + (copyMonkey == monkey));


/*
* 持有的是同一个金箍棒的。 深复制被复制的对象的所有的变量都含有与原来的对象相同的值。
* 深复制使得复制的猴子与猴子本尊对象持有的金箍棒对象是两个独立的对象。
*/
System.out.println("猴王金箍棒==复制猴王金箍棒?"
+ (copyMonkey.getStaff() == monkey.getStaff()));


// 显然两个金箍棒是两个不同的对象
System.out.println("猴王的金箍棒长度" + monkey.getStaff().getHeight());
System.out.println("复制猴王的金箍棒长度" + copyMonkey.getStaff().getHeight());

}


public static void main(String[] args) throws IOException,
ClassNotFoundException {
TheGreatestSageclient sageMonkey = new TheGreatestSageclient();
sageMonkey.change();
}
}


结果打印;
具体原形的无参构造
金箍棒的无参构造
金箍棒的移动方法
猴王生日Tue May 23 15:38:28 GMT+08:00 2017
复制猴王生日Tue May 23 15:38:28 GMT+08:00 2017
猴王==复制猴王?false
猴王金箍棒==复制猴王金箍棒?false
猴王的金箍棒长度50.0
复制猴王的金箍棒长度200.0


上面是利用串行化实现深复制


此外,把对象写到流里的过程是串行化过程,也叫冷冻或者腌咸菜的过程,而把对象从流中读出来的并行化过程叫解冻或者叫回鲜过程。


通过这些实例,相信对该模式有了进一步的认识。

每天努力一点,每天都在进步。