原型模式

​一、原型模式介绍

原型模式:原型模式就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。

所谓原型模式,就是java中的克隆技术,以某个对象为原型。复制出新的对象。显然新的对象具备原型对象的特点。效率高(避免了重新执行构造过程步骤)

克隆类似于new,但和new不同。new创建新的对象属性采用的是默认值。克隆出来的对象的属性值完全和原型对象相同。并且克隆出的新对象不会影响原型对象,克隆后。还可以再修改克隆对象的值。

要实现原型模式,必须实现Cloneable接口,而这个接口里面是空的。

Cloneable接口是一个空接口,使用Cloneable接口都不用导入包。而clone方法是属于Object对象的。如果要克隆某个对象的话必须实现Cloneable接口

1
2
3
4
5
6
7
* @author  unascribed
  * @see     java.lang.CloneNotSupportedException
  * @see     java.lang.Object#clone()
  * @since   JDK1. 0
  */
public interface Cloneable {
}

重写Object对象的clone方法,clone方法为本地方法。效率比较高

1
protected native Object clone() throws CloneNotSupportedException;

如果我们要克隆某个对象有浅克隆和深克隆

浅克隆:copy该对象,然后保留该对象原有的引用。也就是说不克隆该对象的属性。

深克隆:copy该对象,并且把该对象的所有属性也克隆出一份新的。

二、代码实现

1、浅克隆代码实现:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
  * 原型模式:浅克隆
  * Cloneable是一个空接口(标记接口),是一个规范。但是如果要克隆这个类对象的话必须实现Cloneable接口
  */
public class Sheep implements Cloneable{
     private String sname;
     private Date birthday;
     
     /**
      * 重写Object对象的clone方法
      */
     @Override
     protected Object clone() throws CloneNotSupportedException {
         //直接调用Object对象的clone方法
         Object obj = super .clone();
         return obj;
     }
     //省略get,set方法和构造方法
     
}
 
/**
  * 测试原型模式(浅克隆)
  */
public class Test {
     public static void main(String[] args) throws Exception {
         Date date = new Date(1274397294739L);
         Sheep s1 = new Sheep( "原型羊" ,date);
         Sheep s2 = (Sheep) s1.clone(); //克隆一个羊
         System.out.println(s1);
         System.out.println(s1.getSname());
         System.out.println( "原日期:" +s1.getBirthday());
         date.setTime(34732834827389L); //改变原有date的值
         System.out.println( "改变后的日期:" +date.toString());
         
         //克隆羊的信息
         System.out.println( "---------------------------------" );
         System.out.println(s2);
         System.out.println(s2.getSname());
         System.out.println(s2.getBirthday()); //此时的birthday日期使用的是改变后的日期对象引用
     }
}

最后的结果为:克隆的对象仍然保留了原有对象的引用,值随着改变而改变

1
2
3
4
5
6
7
8
com.fz.prototype.Sheep @153f67e
原型羊
原日期:Fri May 21 07 : 14 : 54 CST 2010
改变后的日期:Mon Aug 22 17 : 40 : 27 CST 3070
---------------------------------
com.fz.prototype.Sheep @18f51f
原型羊
Mon Aug 22 17 : 40 : 27 CST 3070

 

2、深克隆代码实现:克隆对象的同时,把该对象的属性也连带着克隆出新的。

深克隆只需要在clone方法中将该对象的属性也克隆即可

1
2
3
4
5
6
7
8
9
10
11
12
/**
  * 重写Object对象的clone方法
  */
@Override
protected Object clone() throws CloneNotSupportedException {
     //直接调用Object对象的clone方法
     Object obj = super .clone();
     //深克隆:把对象下的所有属性也克隆出来
     Sheep22 s = (Sheep22) obj;
     s.birthday = (Date) this .birthday.clone();
     return s;
}

测试代码不变,结果则会变了。克隆了之后把原来的日期改变后,克隆的对象2的属性则不会被影响。

1
2
3
4
5
6
7
8
com.fz.prototype.Sheep2 @15bdc50
原型羊
原日期:Fri May 21 07 : 14 : 54 CST 2010
改变后的日期:Mon Aug 22 17 : 40 : 27 CST 3070
---------------------------------
com.fz.prototype.Sheep2 @18f51f
原型羊
Fri May 21 07 : 14 : 54 CST 2010

 

3、通过序列化和反序列化来实现深克隆对象序列化需要原型对象实现Serializable接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;
 
/**
  * 测试原型模式(利用序列化和反序列化实现深克隆)
  */
public class Test3 {
     public static void main(String[] args) throws Exception {
         Date date = new Date(1274397294739L);
         Sheep s1 = new Sheep( "原型羊" ,date);
//      Sheep s2 = (Sheep) s1.clone();//克隆一个羊
         
         //使用序列化和反序列化实现深复制
         //1、将s1对象序列化为一个数组
         //通过ObjectOutputStream流将s1对象读出来给ByteArrayOutputStream流
         ByteArrayOutputStream bos = new ByteArrayOutputStream();
         ObjectOutputStream    oos = new ObjectOutputStream(bos);
         oos.writeObject(s1);
         //ByteArrayOutputStream流将对象信息转成byte数组,这样byte数组里就包含了对象的数据
         byte [] bytes = bos.toByteArray();
         
         //2、将字节数组中的内容反序列化为一个Sheep对象
         //通过ByteArrayInputStream流读入bytes字节数组中数据,然后传给ObjectInputStream对象输入流
         ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
         ObjectInputStream    ois = new ObjectInputStream(bis);
         //通过ObjectInputStream返回一个Sheep对象
         Sheep s2 = (Sheep) ois.readObject();
 
         //原型羊的信息
         System.out.println(s1);
         System.out.println( "原日期:" +s1.getBirthday());
         date.setTime(34732834827389L); //改变原有date的值
         System.out.println( "改变后的日期:" +date.toString());
         //克隆羊的信息
         System.out.println( "---------------------------------" );
         System.out.println(s2);
         System.out.println(s2.getBirthday());
     }
}

通过序列化和反序列化的结果,最终结果还是和深克隆一样。

1
2
3
4
5
6
7
8
9
10
11
com.fz.prototype.Sheep @1a116c9
 
原日期:Fri May 21 07 : 14 : 54 CST 2010
 
改变后的日期:Mon Aug 22 17 : 40 : 27 CST 3070
 
---------------------------------
 
com.fz.prototype.Sheep @7eb6e2
 
Fri May 21 07 : 14 : 54 CST 2010

 

三、测试克隆对象的效率

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.fz.prototype;
/**
  * 测试clone对象的效率
  */
public class TestClone {
     //new 对象
     public static void testNew( int size){
         long start = System.currentTimeMillis();
         for ( int i = 0 ; i < size; i++) {
             Laptop l = new Laptop();
         }
         long end = System.currentTimeMillis();
         System.out.println( "new 对象耗时:" +(end-start));
     }
     //clone 对象
     public static void testClone( int size){
         long start = System.currentTimeMillis();
         Laptop l = new Laptop();
         for ( int i = 0 ; i < size; i++) {
             try {
                 Laptop temp = (Laptop) l.clone();
             } catch (CloneNotSupportedException e) {
                 e.printStackTrace();
             }
         }
         long end = System.currentTimeMillis();
         System.out.println( "clone 对象耗时:" +(end-start));
     }
     public static void main(String[] args) {
         testNew( 1000 );
         testClone( 1000 );
     }
}
 
class Laptop implements Cloneable{
     public Laptop() {
         //模拟创建Laptop对象的时候比较耗时
         try {
             Thread.sleep( 10 );
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
     }
     @Override
     protected Object clone() throws CloneNotSupportedException {
         return super .clone();
     }
}

最后结果为:

new 对象耗时:10063

clone 对象耗时:10

 

四、使用场景

原型模式适用场景:如果某个对象new的过程中很耗时,则可以考虑使用原型模式。

Spring框架中bean对象的创建就两种模式:单例模式或者原型模式

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值