美文网首页
创建型模式——原型模式(五)

创建型模式——原型模式(五)

作者: 最后的轻语_dd43 | 来源:发表于2019-05-22 08:26 被阅读0次

    该项目源码地址:https://github.com/lastwhispers/code/tree/master/java-basic/design-pattern
    (设计模式相关代码与笔记)

    1. 定义

    指原型实例指定创建对象的种类,并通过克隆这些原型创建新的对象

    2. 适用场景

    • 类初始化消耗较多资源
    • new产生的一个对象需要非常繁琐的过程(数据准备、访问权限等)
    • 构造函数比较复杂
    • 循环体中生产大量对象时

    3. 深浅克隆

    浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
    深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
    总之深浅克隆都会在堆中新分配一块区域,区别在于对象属性引用的对象是否需要进行克隆(递归性的)。

    4. 模式实例

    原型模式就是让类实现Cloneable接口,达到克隆原型类的方式。

    4.1 深浅克隆原型对比

    复印简历各位都应该做过吧!这里我们利用原型模式来模拟复印简历。

    (1)简历类

    import java.util.Date;
    public class Resume implements Cloneable {
        private String name;
        private Date birthday;
        private String sex;
        private String school;
        private String timeArea;
        private String company;
    
        public Resume(String name, Date birthday, String sex, String school, String timeArea, String company) {
            this.name = name;
            this.birthday = birthday;
            this.sex = sex;
            this.school = school;
            this.timeArea = timeArea;
            this.company = company;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Date getBirthday() {
            return birthday;
        }
    
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
    
        public String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    
        public String getSchool() {
            return school;
        }
    
        public void setSchool(String school) {
            this.school = school;
        }
    
        public String getTimeArea() {
            return timeArea;
        }
    
        public void setTimeArea(String timeArea) {
            this.timeArea = timeArea;
        }
    
        public String getCompany() {
            return company;
        }
    
        public void setCompany(String company) {
            this.company = company;
        }
    
        /**
         * 克隆该实例
         */
        @Override
        public Object clone() {
            Resume resume = null;
            try {
                resume = (Resume) super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return resume;
        }
    
        public void display() {
            System.out.println("姓名:" + name);
            System.out.println("生日:" + birthday + ",性别:" + sex + ",毕业学校:" + school);
            System.out.println("工作年限:" + timeArea + ",公司:" + company);
        }
    
    }
    

    (2)测试类

    public class Test {
        public static void main(String[] args) {
            //原型A对象
            Resume a = new Resume("小李子",new Date(), "男", "XX大学","2012.09.05", "XX科技有限公司");
            a.display();
            System.out.println("*************克隆简历**************");
            //克隆B对象
            Resume b = (Resume) a.clone();
            b.display();
            System.out.println("***************比较***************");
            /*
             * 测试A==B?
             * 对任何的对象x,都有x.clone() !=x,即克隆对象与原对象不是同一个对象
             */
            System.out.print("比较:A==B?");
            System.out.println( a == b);
    
            b.getBirthday().setTime(666666666666L);
            System.out.println("修改B简历的Birthday为:"+b.getBirthday());
            System.out.println("查看A简历的Birthday为:"+a.getBirthday());
    
            /*
             * 比较Date对象
             */
            System.out.print("比较:A.Date==B.Date?");
            System.out.println(a.getBirthday() == b.getBirthday());
        }
    }
    

    (3)测试结果

    可以发现B在克隆A的birthday时,是直接克隆的引用。这种是浅克隆。

    浅克隆

    (4)修改为深克隆

    @Override
    public Object clone() {
        Resume resume = null;
        try {
            resume = (Resume) super.clone();
            resume.birthday = (Date) resume.birthday.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return resume;
    }
    

    再次测试,可以发现B在克隆A的birthday时,是重新克隆的birthday,而不是直接克隆的引用。

    深克隆

    4.2 抽象原型类

    public abstract class A implements Cloneable{
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }
    
    public class B extends A{
        public static void main(String[] args) throws CloneNotSupportedException {
            B b = new B();
            b.clone();
        }
    }
    

    5. 优缺点

    优点:

    1. 当创建对象的实例较为复杂的时候,使用原型模式可以简化对象的创建过程,通过复制一个已有的实例可以提高实例的创建效率。
    2. 扩展性好。由于原型模式提供了抽象原型类,在客户端针对抽象原型类进行编程,而将具体原型类写到配置文件中,增减或减少产品对原有系统都没有影响。
    3. 可以使用深克隆方式保存对象的状态。使用原型模式将对象复制一份并将其状态保存起来,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。

    缺点:

    1. 需要为每一个类配置一个克隆方法,而且该克隆方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违反了“开闭原则”。
    2. 在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。

    6. 扩展-JDK1.7源码中的原型模式

    ArrayList的clone()
    HashMap的clone()
    CacheKey的clone()

    相关文章

      网友评论

          本文标题:创建型模式——原型模式(五)

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