java设计模式之原型模式

   原型模式是一种比较简单的设计模式,也非常的容易理解,属于创建型设计模式的一种,只实现一个接口,重写一个方法即可完成原型模式。那么我们就来看看吧。

一、定义

用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。


二、适用情况

创建一些大对象,比较耗时的对象的时候,可以使用原型模式提高创建对象的效率。


三、原型模式实现

1、实现Cloneable接口,在java中有一个Cloneable接口,它的作用只有一个,就是通知虚拟机可以安全的在实现了此接口的类上使用clone()方法。如果你想看下这个接口,其实可以告诉你,并没有什么可看的,只是一个标识接口,实现此接口就是表示了这个类具有被Clone的能力,如果没有实现此接口,而去使用clone(),就会抛出CloneNotSupportedException异常。

2、重写Object类中的clone方法。Java中,所有类的父类都是Object类,Object类中有一个clone方法,作用是返回对象的一个拷贝,但是其作用域protected类型的,一般的类无法调用,因此,Prototype类需要将clone方法的作用域修改为public类型。

下面就以羊来为原型克隆多利

代码实现

package cn.wong.pattern.prototype;

import java.util.Date;

public class Sheep implements Cloneable {

    private String name;
    private Date birthDay;


    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public Sheep() {
    }

    public Sheep(String name, Date birthDay) {
        this.name = name;
        this.birthDay = birthDay;
    }

    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;
    }

}
package cn.wong.pattern.prototype;

import java.util.Date;

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        Sheep s1 = new Sheep("芬兰母羊",new Date(324324234L));
        System.out.println(s1);
        System.out.println(s1.getName());
        System.out.println(s1.getBirthDay());

        System.out.println("---------进行clone----------");
        Sheep s2 = (Sheep)s1.clone();
        System.out.println(s2);
        System.out.println(s2.getName());
        System.out.println(s2.getBirthDay());
    }
}

结果:

cn.wong.pattern.prototype.Sheep@4633c1aa
芬兰母羊
Mon Jan 05 02:05:24 CST 1970
---------进行clone----------
cn.wong.pattern.prototype.Sheep@28a50395
芬兰母羊
Mon Jan 05 02:05:24 CST 1970

从结果可以看出拷贝出来的是一个新的对象,并和原始对象具有相同的属性值

使用原型模式创建对象比直接new一个对象在性能上要好很多,因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。
protected native Object clone() throws CloneNotSupportedException;

使用原型模式的注意事项

1. 使用原型模式不会调用类的构造方法,因为它是直接在内存中进行复制的。
2. 深拷贝和浅拷贝


四、浅拷贝和深拷贝

Object类的clone方法只会拷贝对象中的8中基本数据类型,对于数组、日期、容器对象、引用对象等都不会拷贝,这就是浅拷贝。如果要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝

浅拷贝:

package cn.wong.pattern.prototype;

import java.util.Date;

public class Sheep implements Cloneable {

    private String name;
    private Date birthDay;


    @Override
    public Object clone() throws CloneNotSupportedException {
        Object obj = super.clone();
        /*Sheep s = (Sheep)obj;
        s.birthDay=(Date) this.birthDay.clone();*/
        return obj;
    }

    public Sheep() {
    }

    public Sheep(String name, Date birthDay) {
        this.name = name;
        this.birthDay = birthDay;
    }

    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;
    }

}
package cn.wong.pattern.prototype;

import java.util.Date;

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        Date date = new Date(324324234L);
        Sheep s1 = new Sheep("芬兰母羊",date);
        System.out.println("---------打印s1的信息----------");
        System.out.println(s1);
        System.out.println(s1.getName());
        System.out.println(s1.getBirthDay());
        //进行复制
        Sheep s2 = (Sheep)s1.clone();


        //修改s1所指向的时间
        date.setTime(23432454354L);
        System.out.println("\n---------再次打印s1的信息----------");
        System.out.println(s1.getName());
        System.out.println(s1.getBirthDay());

        System.out.println("\n---------打印s2的信息----------");
        System.out.println(s2);
        System.out.println(s2.getName());
        System.out.println(s2.getBirthDay());
    }
}

结果:

---------打印s1的信息----------
cn.wong.pattern.prototype.Sheep@5df1cc1a
芬兰母羊
Mon Jan 05 02:05:24 CST 1970

---------再次打印s1的信息----------
芬兰母羊
Tue Sep 29 13:00:54 CST 1970

---------打印s2的信息----------
cn.wong.pattern.prototype.Sheep@7a0ec850
芬兰母羊
Tue Sep 29 13:00:54 CST 1970

发现s2的信息是改变时间后的,我们知道,clone是在修改时间前进行。所以由此我们可以知道引用类型对象不会进行拷贝,s1、s2两个对象同时都是指向同一个Date,这就是浅拷贝。

深拷贝:

如果要实现深拷贝,必须将引用对象另行拷贝。而对于java的大部分的类都实现了Cloneable接口,所以深拷贝并不困难。

修改Sheep中clone方法

@Override
    public Object clone() throws CloneNotSupportedException {
        Object obj = super.clone();
        Sheep s = (Sheep)obj;
        s.birthDay=(Date) this.birthDay.clone();
        return obj;
    }

测试不变

package cn.wong.pattern.prototype;

import java.util.Date;

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        Date date = new Date(324324234L);
        Sheep s1 = new Sheep("芬兰母羊",date);
        System.out.println("---------打印s1的信息----------");
        System.out.println(s1);
        System.out.println(s1.getName());
        System.out.println(s1.getBirthDay());
        //进行复制
        Sheep s2 = (Sheep)s1.clone();


        //修改s1所指向的时间
        date.setTime(23432454354L);
        System.out.println("\n---------再次打印s1的信息----------");
        System.out.println(s1.getName());
        System.out.println(s1.getBirthDay());

        System.out.println("\n---------打印s2的信息----------");
        System.out.println(s2);
        System.out.println(s2.getName());
        System.out.println(s2.getBirthDay());
    }
}

结果

---------打印s1的信息----------
cn.wong.pattern.prototype.Sheep@2d8eef25
芬兰母羊
Mon Jan 05 02:05:24 CST 1970

---------再次打印s1的信息----------
芬兰母羊
Tue Sep 29 13:00:54 CST 1970

---------打印s2的信息----------
cn.wong.pattern.prototype.Sheep@60813aca
芬兰母羊
Mon Jan 05 02:05:24 CST 1970
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值