什么是原型模式
原型模式(Prototype Pattern)是五种创建型模式的其中一种,用原型实例指定创建对象的种类作为原型,并且通过拷贝原型来创建新的对象。
为什么要使用原型模式
新建一个对象有时候会很麻烦,可能涉及大量的变量初始化,函数、代码块的执行,不仅浪费资源,还会涉及数据准备、访问权限等操作。
实现
原型模式至少涉及两个角色:
Prototype,即原型类:需要实现Cloneable接口,并重写clone()方法,为外部提供一个克隆自身的方法;Client,即应用类:让一个原型克隆自身从而创建一个新的对象。
public class Prototype implements Cloneable {//自身的一些方法...@Overridepublic Object clone() throws CloneNotSupportedException {Prototype proto = (Prototype) super.clone();return proto;}}public class Client {public static void main(String[] args) throws CloneNotSupportedException {Prototype prototype = new Prototype();Prototype prototype1 = (Prototype) prototype.clone();...}}
为了探讨其中的一些细节,我们对上面的代码稍微添加一些细节部分:
public class Prototype implements Cloneable {private String name;public Prototype() {System.out.println("empty constructor--------------------");}public Prototype(String name) {System.out.println("constructor--------------------");this.name = name;}@Overridepublic Object clone() throws CloneNotSupportedException {Prototype proto = (Prototype) super.clone();return proto;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return super.toString() + " " + this.getName();}}public class Client {public static void main(String[] args) throws CloneNotSupportedException {Prototype prototype = new Prototype();prototype.setName("111");System.out.println(prototype.toString());Prototype prototype1 = (Prototype) prototype.clone();System.out.println(prototype1.toString());prototype1.setName("222");System.out.println(prototype.toString());System.out.println(prototype1.toString());}}
在Prototype类中加入了构造函数,重写了toString(),运行main(),结果如下:
empty constructor--------------------pany.Prototype@4554617c pany.Prototype@74a14482 pany.Prototype@4554617c pany.Prototype@74a14482 222
可以看出:
构造函数只执行了一次,说明复制原型类的对象并不需要执行构造函数;
原对象和复制对象的地址不同,说明是重新创建的;
目前看来,在复制完成之后,复制的对象似乎和原对象就没有关系了,原对象的改变不会影响复制的对象,复制的对象改变也不会影响原对象。
真的是这样吗?
我们修改一下代码:
public class Car {private String color;public Car() {}public Car(String color) {this.color = color;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}}public class Prototype implements Cloneable {private String name;private Car car;public Prototype() {System.out.println("empty constructor--------------------");}public Prototype(String name) {System.out.println("constructor--------------------");this.name = name;}public Prototype(String name, Car car) {this.name = name;this.car = car;}@Overridepublic Object clone() throws CloneNotSupportedException {Prototype proto = (Prototype) super.clone();return proto;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Car getCar() {return car;}public void setCar(Car car) {this.car = car;}@Overridepublic String toString() {return super.toString() + " " + this.getName() + " " + this.getCar().getColor() + " Car" + " " + this.getCar().toString();}}public class Client {public static void main(String[] args) throws CloneNotSupportedException {Prototype prototype = new Prototype();Car car1 = new Car("red");Car car2 = new Car("yel");prototype.setName("111");prototype.setCar(car1);System.out.println(prototype.toString());Prototype prototype1 = (Prototype) prototype.clone();System.out.println(prototype1.toString());prototype1.setName("222");prototype1.setCar(car2);System.out.println(prototype.toString());System.out.println(prototype1.toString());}}
执行结果:
empty constructor--------------------pany.Prototype@4554617c 111 red pany.Car@pany.Prototype@1540e19d 111 red pany.Car@pany.Prototype@4554617c 111 red pany.Car@pany.Prototype@1540e19d 222 yel pany.Car@677327b6
可以看过结果中第4行和第5行,Car的颜色和地址都不一样,我几乎可以得出结论它们确实不是一个对象了,但是这样写其实是有漏洞的,我通过setCar()是显式地改变了这个对象,不能正确得出结论。
再将输出改一下:
public class Client {public static void main(String[] args) throws CloneNotSupportedException {Prototype prototype = new Prototype();Car car1 = new Car("red");prototype.setName("111");prototype.setCar(car1);System.out.println(prototype.toString());Prototype prototype1 = (Prototype) prototype.clone();System.out.println(prototype1.toString());prototype1.setName("222");prototype1.getCar().setColor("black");System.out.println(prototype.toString());System.out.println(prototype1.toString());}}
结果变为:
empty constructor--------------------pany.Prototype@4554617c 111 red Car pany.Car@pany.Prototype@1540e19d 111 red Car pany.Car@pany.Prototype@4554617c 111 black Car pany.Car@pany.Prototype@1540e19d 222 black Car pany.Car@74a14482
所有的Car对象的地址都是同一个,颜色值也一同改变,说明clone()实现的是浅拷贝。
浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型仍指向的还是原对象所指向的地址。 深复制:将一个对象复制后,基本数据类型和引用类型都重新创建。
如果想对引用类型也实现深拷贝,可以采用二进制流读写等操作实现,此处不再详述。
如果觉得《小唐说设计模式————原型模式》对你有帮助,请点赞、收藏,并留下你的观点哦!