原型模式

作者: Haalo | 来源:发表于2020-03-15 23:44 被阅读0次

    原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。属于创建型模式。
    原型模式的核心在于拷贝原型对象。以系统中已存在的一个对象为原型基于内存二进制流进行拷贝。无需经历对象初始化过程。

    原型模式的应用场景

    在代码中经常会遇到大量get ,set 赋值

    public ExamPaper  copy(){
        ExamPaper paper = new ExamPaper();
        paper.setLeftTime(this.getLeftTime);
        paper.setId(this.id);
        paper.setUserId(this.userId);
        paper.setGrade(this.grade);
        paper.setFullScore(this.fullScore); 
        paper.setScore(this.score);
        return paper;
     }
    

    这种写法很常见,而且代码中很多是这样子的,而原型模式就是为了解决这种不优雅而浪费体力的工作。

    原型模式的使用场景

    • 类初始化消耗资源较多。
    • new一个对象需要比较复杂的过程
    • 构造函数比较复杂。

    而且,在JDK中已经帮我们提供了Cloneable接口,我们只需要实现Cloneable接口即可。

    public class PrototypeDemo implements Cloneable {
        private int age ;
        private String name ;
    
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        protected PrototypeDemo clone()  {
            try {
                return (PrototypeDemo) super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
                return null;
            }
        }
    }
    

    测试方法:

     public static void main(String[] args) {
            PrototypeDemo prototypeDemo = new PrototypeDemo();
            prototypeDemo.setAge(1);
            prototypeDemo.setName("A");
            PrototypeDemo clone = prototypeDemo.clone();
            System.out.println(clone.toString());
        }
    ------------------------------------------------------------------------------------------------
    PrototypeDemo{age=1, name='A'}
    

    可是呢,当PrototypeDemo中增加一个List属性的参数时。

    浅克隆

    public class PrototypeDemo implements Cloneable {
        private int age ;
        private String name ;
        private List hobbies;
    //get set节省页面就不写了
        @Override
        protected PrototypeDemo clone()  {
            try {
                return (PrototypeDemo) super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
                return null;
            }
        }
    }
    
    

    测试结果

        public static void main(String[] args) {
            PrototypeDemo prototypeDemo = new PrototypeDemo();
            prototypeDemo.setAge(1);
            prototypeDemo.setName("A");
            List list = new ArrayList(4);
            list.add("a");
            list.add("b");
            list.add("c");
            prototypeDemo.setHobbies(list);
            PrototypeDemo clone = prototypeDemo.clone();
            clone.getHobbies().add("d");
            System.out.println(prototypeDemo);
            System.out.println(clone);
        }
    ------------------------------------------------------------------------------------------------
    PrototypeDemo{age=1, name='A', hobbies=[a, b, c, d]}
    PrototypeDemo{age=1, name='A', hobbies=[a, b, c, d]}
    

    由结果可见,我们希望的clone和prototypeDemo的hobbies值是不一样的,可是输出的结果是一模一样的。说明JDK的clone 方法复制的不是值,而是引用地址。这样子的话,我们修改clone对象中的hobbies值时,prototypeDemo对象中的值也是会一起改变的,这就是浅克隆。那么该如何解决这个问题呢?

    使用序列化进行深克隆

    实现序列化接口

    public class PrototypeDemo implements Cloneable, Serializable {
        private int age ;
        private String name ;
        private List hobbies;
      //篇幅问题  不写get set方法
        @Override
        protected PrototypeDemo clone()  {
            try {
                return (PrototypeDemo) super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
                return null;
            }
        }
    
        protected PrototypeDemo deepClone(){
            try {
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                ObjectOutputStream o = new ObjectOutputStream(outputStream);
                o.writeObject(this);
                ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
                ObjectInputStream in = new ObjectInputStream(inputStream);
                return (PrototypeDemo) in.readObject();
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return null;
        }
    }
    

    测试:

        public static void main(String[] args) {
            PrototypeDemo prototypeDemo = new PrototypeDemo();
            prototypeDemo.setAge(1);
            prototypeDemo.setName("A");
            List list = new ArrayList(4);
            list.add("a");
            list.add("b");
            list.add("c");
            prototypeDemo.setHobbies(list);
            PrototypeDemo clone = prototypeDemo.deepClone();
            clone.getHobbies().add("d");
            System.out.println(prototypeDemo);
            System.out.println(clone);
        }
    ------------------------------------------------------------------------------------------------------
    PrototypeDemo{age=1, name='A', hobbies=[a, b, c]}
    PrototypeDemo{age=1, name='A', hobbies=[a, b, c, d]}
    

    原型模式的优缺点

    优点

    1. 性能提高,Java自带的原型模式是基于内存二进制流的copy。比直接创建一个对象快很多。
    2. 简化对象的创建,使得创建对象就像我们在编辑文档时的复制粘贴一样简单。

    缺点

    1. 每个类都要实现cloneable。
    2. 深克隆与浅克隆。Object类的clone方法只会克隆对象中的基本的数据类型,对于数组、容器对象、引用对象等都不会克隆。如果要实现这些对象的克隆,要编写复杂的代码,而且如果有多重嵌套引用时,必须每一层都要进行深克隆。

    相关文章

      网友评论

        本文标题:原型模式

        本文链接:https://www.haomeiwen.com/subject/ksrpjhtx.html