码迷,mamicode.com
首页 > 编程语言 > 详细

java设计模式(三)——原型模式

时间:2020-07-01 12:47:30      阅读:63      评论:0      收藏:0      [点我收藏+]

标签:修改   turn   vat   exception   src   png   cat   模式   io流   

原型模式属于创造型模式,通过二进制流拷贝已有的对象。

原型模式有浅克隆和深度克隆

案例:

原型接口Iprototype:

public interface Iprototype<T> {

    T clone();

}

 

原对象实现原型接口:

@Data
public class Teacher implements Iprototype<Teacher>{

    private String name;
    private Integer age;
    private String no;
    private String addr;


    @Override
    public Teacher clone() {
        Teacher teacher = new Teacher();
        teacher.setName(this.name);
        teacher.setNo(this.no);
        teacher.setAge(this.age);
        teacher.setAddr(this.addr);
        return teacher;
    }
}

测试类:

public class Test {

    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        teacher.setAddr("wuahn");
        teacher.setAge(20);
        teacher.setName("lilei");
        teacher.setNo("1001");


        Teacher clone = teacher.clone();
        System.out.println("原对象:"+teacher);
        System.out.println("克隆对象:"+clone);

    }
}

输出:

原对象:Teacher(name=lilei, age=20, no=1001, addr=wuahn)
克隆对象:Teacher(name=lilei, age=20, no=1001, addr=wuahn)

这就是一个原型设计,我们自己手写的clone方法,如果属性过多,那么就需要设置很多属性,比较麻烦。

所以实际上我们开发上只需要实现Cloneable接口即可,是jdk为我们提供的。

我们需要覆写clone方法:

@Data
public class Teacher implements Cloneable{

    private String name;
    private Integer age;
    private String no;
    private String addr;


    @Override
    protected Teacher clone() {
        try{
            return (Teacher)super.clone();
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }
}

测试输出的结果和上面一样。

上面的克隆是一种浅克隆,那么浅克隆有什么缺点?

再看一个案例:Teacher类新增一个属性classromes

@Data
public class Teacher implements Cloneable{

    private String name;
    private Integer age;
    private String no;
    private String addr;
    private List<String> classroms;

测试:

public class Test {

    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        teacher.setAddr("wuahn");
        teacher.setAge(20);
        teacher.setName("lilei");
        teacher.setNo("1001");
        List<String> list =  new ArrayList<>();
        list.add("101教室");
        list.add("102教室");
        teacher.setClassroms(list);

        Teacher clone = teacher.clone();
        clone.getClassroms().add("103教室");
        System.out.println("原对象:"+teacher);
        System.out.println("克隆对象:"+clone);

    }
}

输出:

原对象:Teacher(name=lilei, age=20, no=1001, addr=wuahn, classroms=[101教室, 102教室, 103教室])
克隆对象:Teacher(name=lilei, age=20, no=1001, addr=wuahn, classroms=[101教室, 102教室, 103教室])

当我们修改克隆对象的时候,会把原对象也修改掉,这肯定就有问题了,这也是浅克隆的问题了

当对象中引入了其他对象的时候,如集合,数组,Student等类型的属性时,克隆只能复制它们的地址。

所以它们还是指向同一内存空间。

技术图片

 

 

 

 

 

这时候就需要深克隆来解决:使用序列化接口Serializable

使用io流来进行操作。


@Data
public class Teacher implements Cloneable,Serializable{

private String name;
private Integer age;
private String no;
private String addr;
private List<String> classroms;

protected Teacher deepClone() {
try{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);

ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (Teacher)ois.readObject();
}catch (Exception e){
e.printStackTrace();
return null;
}

}

@Override
protected Teacher clone() {
try{
return (Teacher)super.clone();
}catch (Exception e){
e.printStackTrace();
return null;
}
}

}
 

测试:

public class Test {

    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        teacher.setAddr("wuahn");
        teacher.setAge(20);
        teacher.setName("lilei");
        teacher.setNo("1001");
        List<String> list =  new ArrayList<>();
        list.add("101教室");
        list.add("102教室");
        teacher.setClassroms(list);

        Teacher clone = teacher.deepClone();
        clone.getClassroms().add("103教室");
        System.out.println("原对象:"+teacher);
        System.out.println("克隆对象:"+clone);

    }
}

输出:

原对象:Teacher(name=lilei, age=20, no=1001, addr=wuahn, classroms=[101教室, 102教室])
克隆对象:Teacher(name=lilei, age=20, no=1001, addr=wuahn, classroms=[101教室, 102教室, 103教室])

我们可以看到已经解决了浅克隆的问题。

注意点:深克隆会破坏单例模式,所以单例模式下不要去实现cloneable接口

 

在开发中,很多项目都提供了克隆工具,如Apache BeanUtils 和Spring BeanUtils

不推荐使用Apache  BeanUtils,在阿里巴巴的泰山版开发手册中有提到:

技术图片

 

java设计模式(三)——原型模式

标签:修改   turn   vat   exception   src   png   cat   模式   io流   

原文地址:https://www.cnblogs.com/tdyang/p/13218276.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!