原型模式(Prototype)

?一、原型模式介绍

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

所谓原型模式,就是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对象的创建就两种模式:单例模式或者原型模式

来自为知笔记(Wiz)

时间: 2024-10-19 22:45:20

原型模式(Prototype)的相关文章

Design Patterns 5 原型模式 Prototype

原型模式 Prototype 原型模式:用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象. 当我们需要多个相同的类实例时,没必要每次都使用new运算符去创建相同的类实例对象,我们可以用原型模式减少内存的消耗和达到类实例的复用. //带有返回自身接口的抽象原型类 public abstract class Prototype5 { public string Id { get; set; } public Prototype5(string id) { this.Id = id;

二十四种设计模式:原型模式(Prototype Pattern)

原型模式(Prototype Pattern) 介绍用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象. 示例有一个Message实体类,现在要克隆它. MessageModel using System; using System.Collections.Generic; using System.Text; namespace Pattern.Prototype { /// <summary> /// Message实体类 /// </summary> publi

谈谈设计模式~原型模式(Prototype)

返回目录 原型模式是创建型模式的一种,其特点在于通过“复制”一个已经存在的实例来返回新的实例(clone),而不是新建(new)实例.被复制的实例就是我们所称的“原型”,这个原型是可定制的. 原型模式多用于创建复杂的或者耗时的实例,因为这种情况下,复制一个已经存在的实例使程序运行更高效:或者创建值相等,只是命名不一样的同类数据. 从原型模式的概念中,我们可以看到,在这个模式里,拷贝是个很重要的概念,即在不创建对象的情况下,返回一个已有对象,这就是拷贝去实现的,在面向对象的编程世界里,拷贝分为浅拷

设计模式(创建型)之原型模式(Prototype Pattern)

PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! 概述 原型模式是一种创建型设计模式,它通过复制一个已经存在的实例来返回新的实例,而不是新建实例.被复制的实例就是我们所称的原型,这个原型是可定制的.原型模式多用于创建复杂的或者耗时的实例, 因为这种情况下,复制一个已经存在的实例可以使程序运行更高效,或者创建值相等,只是命名不一样的同类数据. 原型模式要求对象实现一个可以"克隆"自身的接口,这样就可以通过

【设计模式】—— 原型模式Prototype

前言:[模式总览]——————————by xingoo 模式意图 由于有些时候,需要在运行时指定对象时哪个类的实例,此时用工厂模式就有些力不从心了.通过原型模式就可以通过拷贝函数clone一个原有的对象,给现在的对象使用,从而创建更多的同类型的对象. 模式结构 [简单原型模式]用于原型的版本不多的时候 [登记模式的原型模式]如果原型的实现很多种版本,那么通过一个登记管理类,可以方便的实现原型的管理. Prototype 原型接口,定义原型的结构. ConcretePrototype 原型的具体

[工作中的设计模式]原型模式prototype

一.模式解析 提起prototype,最近看多了js相关的内容,第一印象首先是js的原型 var Person=function(name){ this.name=name; } Person.prototype.run=function(){ alert(this.name+" is running"; } 此处的原型是js的特殊定义,在原型上定义的属性和方法所有的类进行共享. 不过设计模式中的原型模式指的是:将已有的对象作为原型,拷贝出一份具有相同属性的新的对象. 模式定义为:原型

设计模式之六:原型模式(Prototype)

原型模式:使用原型实例来指定创建对象的种类,并通过拷贝这个对象的值来创建新的对象. Specify the kind of objects to create using a prototypical instance, and create new objects by copying this prototype. UML图: 主要包括 Prototype:定义了一个包含克隆自身的接口 ConcretePrototype:具体的原型类,实现了克隆自身函数的类 Client:通过一个具体的原型

设计模式 笔记 原型模式 prototype

//---------------------------15/04/07---------------------------- //prototype 原型模式--对象创建型模式 /* 1:意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 2:动机: 3:适用性: 1>当一个系统应该独立于它的产品创建.构成和表示时 2>当要实例化的类是在运行时刻制定时,例如通过动态装载 3>为了避免创建一个与产品类层次平行的工厂类层次时 4>当一个类的实例只能有几个不同状

设计模式(四)原型模式Prototype(创建型)

1.   概述 我们都知道,创建型模式一般是用来创建一个新的对象,然后我们使用这个对象完成一些对象的操作,我们通过原型模式可以快速的创建一个对象而不需要提供专门的new()操作就可以快速完成对象的创建,这无疑是一种非常有效的方式,快速的创建一个新的对象. 例子1:孙悟空拔下一嘬猴毛,轻轻一吹就会变出好多的孙悟空来. 例子2:寄个快递下面是一个邮寄快递的场景:“给我寄个快递.”顾客说.“寄往什么地方?寄给……?”你问.“和上次差不多一样,只是邮寄给另外一个地址,这里是邮寄地址……”顾客一边说一边把

原型模式Prototype,constructor,__proto__详解

最近由于在找工作,又拿起<JavaScript高级程序设计>看了起来,从中也发现了自己确实还是有很多地方不懂,刚刚看到原型模式这里,今天终于搞懂了,当然,我也不知道自己的理解是否有错. 1.prototype 开头第一句话说,我们每创建一个函数,就会有一个prototype属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含由特定类型或者实例共享的属性和方法. function fn(){}; console.log(fn.prototype); 其实 其实我们创建函数就是调用构造函