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


    1、基本概念

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

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

    2、原型类型

    2.1、浅克隆

    案例:

    原型接口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类新增一个属性classroms

    @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

    2.2、深克隆

    使用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,在阿里巴巴的泰山版开发手册中有提到:

  • 相关阅读:
    web端
    vue 键盘事件keyup/keydoen
    APiCloud
    APiCloud
    对于HTML和XML的理解
    JS 的三种定义变量 var let const
    jQuery
    NodeJS 阻塞/非阻塞
    NodeJs REPL交互式解析器常用命令
    用NodeJS创建一个聊天服务器
  • 原文地址:https://www.cnblogs.com/tdyang/p/13218276.html
Copyright © 2020-2023  润新知