原型模式
用原型模式指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
模型图
代码
public interface Prototype extends Cloneable {}
public class ConcreatePrototype1 implements Prototype{
private ConcreatePrototype2 ConcreatePrototype2=null;
public ConcreatePrototype2 getConcreatePrototype2() {
return ConcreatePrototype2;
}
public void setConcreatePrototype2(ConcreatePrototype2 concreatePrototype2) {
ConcreatePrototype2 = concreatePrototype2;
}
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
private String filed1;
public ConcreatePrototype1(String filed1, String filed2) {
super();
this.filed1 = filed1;
this.filed2 = filed2;
}
private String filed2;
public String getFiled1() {
return filed1;
}
public void setFiled1(String filed1) {
this.filed1 = filed1;
}
public String getFiled2() {
return filed2;
}
public void setFiled2(String filed2) {
this.filed2 = filed2;
}
@Override
public String toString() {
return "ConcreatePrototype1 [ConcreatePrototype2="
+ ConcreatePrototype2 + ", filed1=" + filed1 + ", filed2="
+ filed2 + "]";
}
}
public class ConcreatePrototype2 implements Prototype {
private String filed;
public String getFiled() {
return filed;
}
public void setFiled(String filed) {
this.filed = filed;
}
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
@Override
public String toString() {
return "ConcreatePrototype2 [filed=" + filed + "]";
}
public ConcreatePrototype2(String filed) {
super();
this.filed = filed;
}
}
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
ConcreatePrototype1 concreatePrototype1=new ConcreatePrototype1("1","1");
concreatePrototype1.setConcreatePrototype2(new ConcreatePrototype2("1"));
System.out.println(concreatePrototype1);
ConcreatePrototype1 clone = (ConcreatePrototype1) concreatePrototype1.clone();
clone.getConcreatePrototype2().setFiled("2");
System.out.println(clone);
}
}
结果
案例
需求 穿件一个份原始的简历,在不对原始简历做变更的情况下,快速创建出几分相同的简历来,这几分简历都在原始简历的基础上做微调
分析与设计
原始对象不做变更,基于原始对象,创建相同的对象适合原型模式
结构图
代码
public interface ProtoType extends Cloneable {
}
public class Resume implements ProtoType{
private String name;
private int age;
private int sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Resume [name=" + name + ", age=" + age + ", sex=" + sex + "]";
}
public Resume(String name, int age, int sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
}
public void setAge(int age) {
this.age = age;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
}
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Resume resume=new Resume("张三",1,2);
System.out.println(resume);
Resume clone = (Resume) resume.clone();
clone.setAge(3);
System.out.println(clone);
}
}
深拷贝:复制一个对象,如果这个对象里面的字段是引用类型的,那么同样也拷贝这个引用类型,变更当前拷贝对象
引用类型的值。原引用对象的值不变
浅拷贝:复制一个对象,如果这个对象里面的字段是引用类型的,那么拷贝的引用的对象的引用还是指向原有的对象,
更改当前拷贝对象,引用对象的值。原引用对象会跟着改变。
如上代码所示Java默认的原型模式是浅拷贝的如上图所示,我们修改了拷贝对象的引用对象的值以后。再次回去打印原对象的时候我们发现,concreteProTotype中的filed值已经不是1变成了2.这就证明所有的实例中的引用对象引用的是同一个对象。
那么我们怎么用java来实现深拷贝呢,两种方式
方式一 对象克隆方式
修改原ConcretePrototype中的克隆方法,再对引用对象做一次浅拷贝,这种克隆方式,需要你对对象里面的多级调用都
再这个方法里进行浅拷贝,也就是递归的对象浅拷贝来实现对象的深拷贝。如果对象组合层次比较深的话,不建议使用这种方式来做深拷贝。也不具有通用性。
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
ConcreatePrototype1 clone = (ConcreatePrototype1) super.clone();
ConcreatePrototype2 concreatePrototype22 = (xiao.it.designer.prototype.model.ConcreatePrototype2) clone.getConcreatePrototype2().clone();
clone.setConcreatePrototype2(concreatePrototype22);
return clone;
}
结果
如图所示成功的实现了深拷贝
在直接写序列化流方式前先讲一下对象序列化,往往在很多时候做对象远程传输
与对象磁盘存储的时候,总是需要先对对象进项序列化的。
自定义抽象的序列化类
public abstract class Serializers<T> {
public abstract T read(byte[] buf) throws IOException, ClassNotFoundException;
public abstract byte[] wirte(T t) throws IOException;
}
序列化工具
/**
*
*/
package com.java;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* @author pc
* @param <T>
*
*/
public class SerializeUtils<T> extends Serializers<T> {
private static SerializeUtils serializeUtils=null;
private SerializeUtils() {
}
public static SerializeUtils getInstance() {
if(null==serializeUtils) {
synchronized (SerializeUtils.class) {
if(null==serializeUtils) {
serializeUtils=new SerializeUtils();
}
}
}
return serializeUtils;
}
/*
* (non-Javadoc)
*
* @see com.java.Serializers#read(byte[])
*/
@Override
public T read(byte[] buf) throws IOException, ClassNotFoundException {
ByteArrayInputStream arrayInputStream = new ByteArrayInputStream(buf);
ObjectInputStream inputStream = new ObjectInputStream(arrayInputStream);
T readObject = (T) inputStream.readObject();
return readObject;
}
@Override
public byte[] wirte(T t) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(byteArrayOutputStream);
outputStream.writeObject(t);
byte[] byteArray = byteArrayOutputStream.toByteArray();
return byteArray;
}
}
对象类记得实现Serializable接口
/**
*
*/
package com.java;
import java.io.Serializable;
/**
* @author pc
*
*/
public class User implements Serializable{
private int no;
private String name;
private String age;
public User() {
}
@Override
public String toString() {
return "User [no=" + no + ", name=" + name + ", age=" + age + "]";
}
public User(int no,String name,String age) {
this.no=no;
this.name=name;
this.age=age;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
测试类
public class SerializeTest {
@SuppressWarnings("unchecked")
public static void main(String[] args) throws IOException, ClassNotFoundException {
User user=new User(123, "xiaozhengwen", "xxxx");
//定义
byte[] wirte = SerializeUtils.getInstance().wirte(user);
System.out.println(Arrays.toString(wirte));
User read = (User) SerializeUtils.getInstance().read(wirte);
System.out.println(read);
}
}
测试结果
由上图可以看出实际上对象的序列化,就是把对象转化成,字节码的流文件。再通过字节码把的流文件进行
解析,反序列化成对象。说完了序列化以后,我们再来看通过序列化进行对象的深拷贝的方法。
方式二 序列化流的方式
public class ConcreatePrototype1 implements Serializable,Cloneable{
private ConcreatePrototype2 ConcreatePrototype2=null;
public ConcreatePrototype2 getConcreatePrototype2() {
return ConcreatePrototype2;
}
@Override
protected Object clone() throws CloneNotSupportedException {
ObjectInputStream ois=null;
try {
// 序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
// 反序列化
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
if(null!=ois){
return ois.readObject();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public void setConcreatePrototype2(ConcreatePrototype2 concreatePrototype2) {
ConcreatePrototype2 = concreatePrototype2;
}
private String filed1;
public ConcreatePrototype1(String filed1, String filed2) {
super();
this.filed1 = filed1;
this.filed2 = filed2;
}
private String filed2;
public String getFiled1() {
return filed1;
}
public void setFiled1(String filed1) {
this.filed1 = filed1;
}
public String getFiled2() {
return filed2;
}
public void setFiled2(String filed2) {
this.filed2 = filed2;
}
@Override
public String toString() {
return "ConcreatePrototype1 [ConcreatePrototype2="
+ ConcreatePrototype2 + ", filed1=" + filed1 + ", filed2="
+ filed2 + "]";
}
}
如上代码所示,实现Serializable,Cloneable接口,对clone方法进行重写,就可以实现深拷贝了。这种方式可以写成一个公共的父类实现所有对象的深拷贝,推荐使用。
场景
原始对象不做变更,基于原始对象,创建相同的对象适合原型模式