java 设计模式 prototype_java设计模式(五)原型模式(Prototype)

介绍

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。 Prototype原型模式是一种创建型设计模式,Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。它主要面对的问题是:“某些结构复杂的对象”的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是他们却拥有比较稳定一致的接口。

原型模式虽然是创建型的模式,但是与工程模式没有关系,从名字即可看出,该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象。通过对象的复制,进行讲解。

在Java中,复制对象是通过clone()实现的,先创建一个原型类:1

2

3

4

5

6public class implements Cloneable{

public Object clone() throws CloneNotSupportedException{

Prototype proto = (Prototype) super.clone();

return proto;

}

}

很简单,一个原型类,只需要实现Cloneable接口,覆写clone方法,此处clone方法可以改成任意的名称,因为Cloneable接口是个空接口,你可以任意定义实现类的方法名,如cloneA或者cloneB,因为此处的重点是super.clone()这句话,super.clone()调用的是Object的clone()方法,而在Object类中,clone()是native的。

原型模式最大的特点是克隆一个现有的对象,这个克隆的结果有2种,一种是是浅复制,另一种是深复制,创建型模式一般是用来创建一个新的对象,然后我们使用这个对象完成一些对象的操作,通过原型模式可以快速的创建一个对象而不需要提供专门的new()操作就可以快速完成对象的创建,这无疑是一种非常有效的方式,快速的创建一个新的对象。

结合对象的浅复制和深复制来说一下,首先需要了解对象深、浅复制的概念:浅复制将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。

深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底。

原型模式原理图:

4d9325206e4a13385e981903dd5f9472.png

一个深浅复制的例子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

43

44public class implements Cloneable, Serializable{

private static final long serialVersionUID = 1L;

private String string;

private SerializableObject obj;

public Object clone() throws CloneNotSupportedException{

Prototype proto = (Prototype) super.clone();

return proto;

}

/* 深复制 需要实现Cloneable和Serializable接口 */

public Object deepClone() throws IOException, ClassNotFoundException{

/* 写入当前对象的二进制流 */

ByteArrayOutputStream bos = new ByteArrayOutputStream();

ObjectOutputStream oos = new ObjectOutputStream(bos);

oos.writeObject(this);

/* 读出二进制流产生的新对象 */

ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());

ObjectInputStream ois = new ObjectInputStream(bis);

return ois.readObject();

}

public String getString(){

return string;

}

public void setString(String string){

this.string = string;

}

public SerializableObject getObj(){

return obj;

}

public void setObj(SerializableObject obj){

this.obj = obj;

}

}

class SerializableObject implements Serializable{

private static final long serialVersionUID = 1L;

}

要实现深复制,需要采用流的形式读入当前对象的二进制输入,再写出二进制数据对应的对象。

测试类: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

27public class Test{

public static void main(String[] args)throws CloneNotSupportedException,ClassNotFoundException ,IOException{

Prototype pt=new Prototype();

SerializableObject obj=new SerializableObject();

pt.setObj(obj);

pt.setStr("Hello World");

System.out.println("使用浅克隆方法进行创建对象");

Prototype pt1=(Prototype)pt.clone();

System.out.println("=============================");

System.out.println("比较pt和pt1的str的值:");

System.out.println(pt.getStr());

System.out.println(pt1.getStr());

System.out.println("修改pt1对象中str的值后,比较pt和pt1的str的值:");

pt1.setStr("你好,世界");

System.out.println(pt.getStr());

System.out.println(pt1.getStr());

System.out.println("============================");

System.out.println("比较pt和pt1中temp对象的值");

System.out.println(pt.getObj());

System.out.println(pt1.getObj());

System.out.println("使用深克隆方法进行创建对象");

System.out.println("============================");

pt1=(Prototype)pt.deepClone();

System.out.println(pt.getObj());

System.out.println(pt1.getObj());

}

}

测试结果:1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18/*

使用浅克隆方法进行创建对象

=============================

比较pt和pt1的str的值:

Hello World

Hello World

修改pt1对象中str的值后,比较pt和pt1的str的值:

Hello World

你好,世界

============================

比较pt和pt1中temp对象的值

使用深克隆方法进行创建对象

============================

*/

从上面的输出结果我们可以看出使用Object.clone()方法只能浅层次的克隆,即只能对那些成员变量是基本类型或String类型的对象进行克隆,对哪些成员变量是类类型的对象进行克隆要使用到对象的序列化,不然克隆克隆出来的Prototype对象都共享同一个obj实例。

模型分析

Java语言提供的clone()方法将对象复制了一份并返回给调用者。一般而言,clone()方法满足:对任何的对象x,都有x.clone() !=x,即克隆对象与原对象不是同一个对象。

对任何的对象x,都有x.clone().getClass()==x.getClass(),即克隆对象与原对象的类型一样。

如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。

浅拷贝:一定要实现Cloneable接口(否则CloneNotSupportedException异常)。

深拷贝;实现Cloneable 和Serializable接口。

原型模式优缺点优点当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,通过一个已有实例可以提高新实例的创建效率。

可以动态增加或减少产品类。

原型模式提供了简化的创建结构。

可以使用深克隆的方式保存对象的状态。

缺点需要为每一个类配备一个克隆方法,而且这个克隆方法需要对类的功能进行通盘考虑,这对全新的类来说不是很难,但对已有的类进行改造时,不一定是件容易的事,必须修改其源代码,违背了开闭原则。

在实现深克隆时需要编写较为复杂的代码。

总结

原型模式作为创建型模式中的最特殊的一个模式,具体的创建过程,是由对象本身提供,这样我们在很多的场景下,我们可以很方便的快速的构建新的对象,就像前面分析讲解的几类场景中,可能我们通过使用对象的克隆,比通过其他几类的创建型模式,效果要好的多,而且代价也小很多。

打个比方,原型模式对于系统的扩展,可以做到无缝的扩展,为什么这么说呢?比如其他的创建型工厂,如果新增一个对象类型,那么我们不管是修改配置文件的方式,还是修改代码的形式,无疑我们都是需要进行修改的,对于我们大家通用的公共应用来说这无疑是危险的,那么通过原型模式,则可以解决这样的问题,因为类型本身实现这样的方法即可,但是也有一定的缺点,每个对象都实现这样的方法,无疑是很大的工作量,但是在某些特殊的环境下,或者实际的项目中,可能原型模式是好的选择。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值