所谓原型模式就是用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。在原型模式中,所发动创建的对象通过请求原型对象来拷贝原型对象自己来实现创建过程,当然所发动创建的对象需要知道原型对象的类型。在拷贝中又分为深拷贝和浅拷贝。
浅拷贝:只是赋值了一个内存地址的引用,相当于赋值。
深拷贝:相当于重新new一个新的对象,内存地址和之前对象的不一样。在深拷贝中对于对象的引用默认是浅拷贝,要实现完全的深拷贝,需要对对象的引用也实现深拷贝。
因此可以看出原型设计模式和深拷贝和浅拷贝有莫大的关联。
通过以下案例说明原型设计模式:
一、浅拷贝
class Person {
private String name;
private int age;
private String height;
private Car car;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getHeight() {
return height;
}
public void setHeight(String height) {
this.height = height;
}
public Car getCar() {
return car;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", height='" + height + '\'' +
", car=" + car +
'}';
}
public void setCar(Car car) {
this.car = car;
}
}
class Car {
private String name;
private String color;
public Car(String name, String color) {
this.name = name;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", color='" + color + '\'' +
'}';
}
}
上面创建了两个类Person和Car,这两个类是单独的类,现在创建两个Person,一个桶new关键字在堆内存中创建,另一个通过浅拷贝进行赋值,如下:
public static void main(String[] args) {
Person person = new Person();
person.setAge(10);
person.setName("张三");
person.setHeight("1.2米");
person.setCar(new Car("宝马","蓝色"));
System.out.println(person.toString());
Person person2 = person;
person2.setAge(50);
System.out.println(person2.toString());
System.out.println(person.toString());
}
如上person2为浅拷贝,运行打印如下:
发现person1和person2的值一样,说明person2还是指向person1的内存地址,并不是一个新的对象。
二、不完全深拷贝
以上演示了浅拷贝,如果让Person实现Cloneable接口,重写clone方法,那么就可以实现深拷贝,即person2是从person1克隆过来,两个不同的内存地址,初始值也和person1一样,这时候改变person2的age属性,不会影响person1的值了。如下:
class Person implements Cloneable {
private String name;
private int age;
private String height;
private Car car;
@Override
protected Person clone() {
Person person = null;
try {
person = (Person) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return person;
}
......
}
再次运行打印如下:
可以看出person1和person2的age属性不一样。
三、完全深拷贝
以上的深拷贝属于不完全的深拷贝,在基本数据类型变量中能够实现深拷贝,但是在引用数据类型中还是没有克隆,只是一个引用。在上面的Person类中引用Car,我们尝试更换Car属性进行比较:
public static void main(String[] args) {
Person person = new Person();
person.setAge(10);
person.setName("张三");
person.setHeight("1.2米");
Car car = new Car("宝马", "蓝色");
person.setCar(car);
System.out.println(person.toString());
Person person2 = person.clone();
car.setColor("#ffffff");
System.out.println(person2.toString());
System.out.println(person.toString());
}
打印结果如下:
可以看出person1和person2的Car属性的color还是一样的。
这种情况就属于不完全的深拷贝,要实现完全的深拷贝,需要对对象的引用也实现深拷贝,因此对Car也实现深拷贝,如下:
class Car implements Cloneable{
private String name;
private String color;
@Override
protected Car clone() throws CloneNotSupportedException {
return (Car) super.clone();
}
}
仅仅这样还不够,需要在Person类中操作。
class Person implements Cloneable {
private String name;
private int age;
private String height;
private Car car;
@Override
protected Person clone() {
Person person = null;
try {
person = (Person) super.clone();
person.car = car.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return person;
}
}
再次查看控制台打印:
可以看出Car的color已经发生变化了。
以上就是原型设计模式的案例。
四、原型设计模式总结
1、优点
- 如果创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率。
- 可以使用深克隆保持对象的状态。
- 原型模式提供了简化的创建结构。
2、缺点
- 在实现深克隆的时候可能需要比较复杂的代码。
- 需要为每一个类配备一个克隆方法,而且这个克隆方法需要对类的功能进行通盘考虑,这对全新的类来说不是很难,但对 已有的类进行改造时,不一定是件容易的事,必须修改其源代码,违背了“开闭原则”。