设计模式之原型模式
原型模式与构造器模式、单例模式、工厂方法模式、抽象工厂模式一样,都属于创建型模式。它用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。当需要创建多个实例,而new一个对象需要非常繁琐的数据准备和访问权限时,用原型模式就再合适不过了。原型模式主要用于对象的复制,它的核心是就是类图中的原型类Prototype。Prototype类需要具备以下两个条件:
1、实现Cloneable接口。在java语言有一个Cloneable接口,它的作用只有一个,就是在运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法。在java虚拟机中,只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出CloneNotSupportedException异常。
2、重写Object类中的clone方法。Java中,所有类的父类都是Object类,Object类中有一个clone方法,作用是返回对象的一个拷贝,但是其作用域protected类型的,一般的类无法调用,因此,Prototype类需要将clone方法的作用域修改为public类型。
原型模式很简单,一个实现了Cloneable接口的类基本就是核心了,来个例子:
class Message implements Cloneable { private String header; private String content; public String getHeader() { return header; } public void setHeader(String header) { this.header = header; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public Message clone() throws CloneNotSupportedException { Message message = (Message) super.clone(); return message; } }
这是一个Message类,它有两个字段以及对应的get、set方法,这只是个例子,事实上只有两个字段的情况下new起来还是很容易的,但是如果有十来个,那就挺麻烦的了。用原型模式只需要在第一个new出来的对象上调用Clone()方法就好了
public static void main(String[] args) { Message msg = new Message(); msg.setHeader("Bank Of China!"); msg.setContent("中国银行开业大酬宾。。。"); try { Message msgCopy = msg.clone(); msgCopy.setHeader("Bank Of America"); }catch(CloneNotSupportedException e) { e.printStackTrace(); } }
这样就可以很容易地制造出许多副本,修改他们不同的地方之后,就可以独自使用了。需要注意的是,java里提供的Object类的clone方法只会拷贝对象中的基本的数据类型,对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。如果要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝。我们可以测试一下:
public static void main(String[] args) { Message msg = new Message(); msg.setHeader("Bank Of China!"); msg.setContent("中国银行开业大酬宾。。。"); try { Message msgCopy = msg.clone(); msgCopy.setHeader("Bank Of America"); System.out.println(msg.getHeader()==msgCopy.getHeader()); System.out.println(msg.getContent()==msgCopy.getContent()); }catch(CloneNotSupportedException e) { e.printStackTrace(); } }
运行可以看到打印出来的是false和true。要实现里面的引用对象深拷贝怎么办,对于自身具有clone方法的引用对象,再调用一下其clone方法就OK了,对于没有的,最简单的用字节流读写一下就好了。