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

该项目源码地址: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()

你可能感兴趣的:(创建型模式——原型模式(五))