设计模式之——原型设计模式

原型设计模式是用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。简单来说就是对象的拷贝过程。所以其优点也是很突出的:使用原型模式创建对象比直接new一个对象在性能上要好的多,因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显


所要具备的条件:

  • 实现Cloneable接口。在java语言有一个Cloneable接口,它的作用只有一个,就是在运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法。在java虚拟机中,只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出CloneNotSupportedException异常。
  • 重写Object类中的clone方法。Java中,所有类的父类都是Object类,Object类中有一个clone方法,作用是返回对象的一个拷贝,但是其作用域protected类型的,一般的类无法调用。

原型模式的注意事项:

  • 使用原型模式复制对象不会调用类的构造方法。因为对象的复制是通过调用Object类的clone方法来完成的,它直接在内存中复制数据,因此不会调用到类的构造方法。不但构造方法中的代码不会执行,甚至连访问权限都对原型模式无效。单例模式中,只要将构造方法的访问权限设置为private型,就可以实现单例。但是clone方法直接无视构造方法的权限,所以,单例模式与原型模式是冲突的,在使用时要特别注意。
  • 深拷贝与浅拷贝。Object类的clone方法只会拷贝对象中的基本的数据类型(8种基本数据类型byte,char,short,int,long,float,double,boolean),对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。如果要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝。

引用的复制:
Person p = new Person(23, "zhang");
Person p1 = p;
		
System.out.println(p);
System.out.println(p1);		
当Person p1 = p;执行之后, 是创建了一个新的对象吗? 
com.pansoft.zhangjg.testclone.Person@2f9ee1ac
com.pansoft.zhangjg.testclone.Person@2f9ee1ac

对象的复制:
Person p = new Person(23, "zhang");
Person p1 = (Person) p.clone();
		
System.out.println(p);
System.out.println(p1);
从打印结果可以看出,两个对象的地址是不同的,也就是说创建了新的对象, 而不是把原对象的地址赋给了一个新的引用变量:
com.pansoft.zhangjg.testclone.Person@2f9ee1ac
com.pansoft.zhangjg.testclone.Person@67f1fba0


言归正传,我们可以看出,该模式的核心就在于clone方法的使用,举个例子:

package com.zndroid.dm.PrototypeModel;

/**
 * Created by luzhenyu on 2016/9/28.
 */
public class Resume implements Cloneable {//简历类实现可clone接口
    private String name;//同一个人的简历中该属性应该是不会变化的
    private String age;
    private String sex;
    private String workTimeArea;
    private String company;

    private Work mWork;//引用类型  需要深复制
    private Apartment mApartment;

    public Resume(String name) {
        this.name = name;
        this.mWork = new Work();
        this.mApartment = new Apartment();
    }

    public void setPersonInfo(String age, String sex) {
        this.age = age;
        this.sex = sex;
    }

    public void setApartment(String place) {
        this.mApartment.setPlace(place);
    }

    public void setWorkExperience(String workTimeArea, String company) {
        this.workTimeArea = workTimeArea;
        this.company = company;

        mWork.setWorkTimeArea(workTimeArea);
        mWork.setCompany(company);
    }

    public void display() {
        System.out.println("name=" + name + " sex=" + sex + " age=" + age
                + " work=" + mWork.getWorkTimeArea() + " company=" + mWork.getCompany() + " place=" + mApartment.getPlace());

        System.out.println("【" + mWork.toString() + " " + mApartment.toString() + "】");
    }

    /**
     * 1、由于clone方法是由虚拟机直接复制内存块执行,所以在速度上比使用new的方式创建对象要快。
     * 2、可以基于原型,快速的创建一个对象,而无需知道创建的细节。
     * 3、可以在运行时动态的获取对象的类型以及状态,从而创建一个对象。
     * 4、主要的缺点就是实现深度拷贝比较困难,需要很多额外的代码量
     *
     * 对于值类型潜拷贝没有问题,对于引用类型需要进行深拷贝
     * */
    @Override
    public Object clone() {//该模式  关键在于此
        //潜复制
        /*try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }*/

        //深复制
        //有几个引用类型就需要分别对该引用类型复制,所引用类型要实现Cloneable接口
        Object o = null;
        try {
            o = super.clone();
            ((Resume)o).mWork = this.mWork.clone();
            ((Resume)o).mApartment = this.mApartment.clone();

            return o;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }


        return null;
    }

    class Work implements Cloneable {
        private String workTimeArea;
        private String company;

        public String getWorkTimeArea() {
            return workTimeArea;
        }

        public void setWorkTimeArea(String workTimeArea) {
            this.workTimeArea = workTimeArea;
        }

        public String getCompany() {
            return company;
        }

        public void setCompany(String company) {
            this.company = company;
        }

        @Override
        public Work clone() {
            try {
                return (Work) super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

    class Apartment implements Cloneable {
        private String place;

        public String getPlace() {
            return place;
        }

        public void setPlace(String place) {
            this.place = place;
        }

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

使用方式:

//案例  一个人在不同阶段的简历
Resume mResume = new Resume("hy");
mResume.display();
log("1111 = " + mResume.toString());
//
Resume mResume2 = (Resume) mResume.clone();
mResume2.setWorkExperience("xuexiao", "null");
mResume2.setmApartment("xuzhou");
mResume2.setPersonInfo("22", "nv");
mResume2.display();
log("2222 = " + mResume2.toString());
//
Resume mResume3 = (Resume) mResume2.clone();
mResume3.setWorkExperience("suzhou", "alibaba");
mResume3.setApartment("suzhou");
mResume3.setPersonInfo("24", "nv");
mResume3.display();
log("3333 = " + mResume3.toString());
//
log("----------------我是分割线-----------------");

【欢迎上码】

【微信公众号搜索 h2o2s2】


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值