原型模式定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
原型模式类图如下:
我们来看下下面的代码
public class Brand {
private String name;
private int age;
public Brand(String name, int age){
this.name = name;
this.age = age;
}
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 class Car {
private int height;
private int weight;
private String country;
private Brand brand;
public Car(int height, int weight, String country, Brand brand){
this.height = height;
this.weight = weight;
this.country = country;
this.brand = brand;
}
public void getInfo(){
System.out.println("height : " + height);
System.out.println("weight : " + weight);
System.out.println("country : " + country);
System.out.println("brand name : " + brand.getName());
System.out.println("brand age : " + brand.getAge());
}
}
public class Buyer {
public List<Car> buy(int num){
List<Car> cars = new LinkedList<>();
if(num == 1){
Car car = new Car(2, 10, "Germany",
new Brand("Benz", 2018));
cars.add(car);
}else{
Car car1 = new Car(2, 10, "Germany",
new Brand("Benz", 2018));
cars.add(car1);
Car car2 = new Car(2, 10, "Germany",
new Brand("Benz", 2018));
cars.add(car2);
}
return cars;
}
}
Car类的构造函数仅有4个参数,还不算特别多,如果Car类的构造函数有40个参数怎么办,每次实例化的时候都要传入40个参数实在是太麻烦
Java中提供了Cloneable接口,以便通过拷贝已有对象实例生成新的实例
public class Car implements Cloneable {
private int height;
private int weight;
private String country;
private Brand brand;
public Car(int height, int weight, String country, Brand brand){
this.height = height;
this.weight = weight;
this.country = country;
this.brand = brand;
}
public void getInfo(){
System.out.println("height : " + height);
System.out.println("weight : " + weight);
System.out.println("country : " + country);
System.out.println("brand name : " + brand.getName());
System.out.println("brand age : " + brand.getAge());
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public Brand getBrand() {
return brand;
}
public void setBrand(Brand brand) {
this.brand = brand;
}
}
public class Buyer {
public List<Car> buy(int num) throws Exception {
List<Car> cars = new LinkedList<>();
if(num == 1){
Car car = new Car(2, 10, "Germany",
new Brand("Benz", 2018));
cars.add(car);
}else{
Car car1 = new Car(2, 10, "Germany",
new Brand("Benz", 2018));
cars.add(car1);
Car car2 = (Car)car1.clone();
cars.add(car2);
}
return cars;
}
}
使用测试类进行测试
public class Test {
public static void main(String[] args) throws Exception {
Buyer buyer = new Buyer();
List<Car> cars = buyer.buy(2);
cars.get(0).getBrand().setName("BMW");
for(Car c : cars){
System.out.println(c.getBrand().getName());
System.out.println(c.getBrand().hashCode());
}
}
}
执行结果如下
BMW
1329552164
BMW
1329552164
从执行结果我们可以发现Object类提供的clone方法进行的是浅表复制,即:如果属性是基本类型,则进行值复制,如果属性是对象类型,则仅进行引用复制(我们常用的Apache的commons-beanutils提供的对象属性复制方法也是浅表复制)
protected native Object clone() throws CloneNotSupportedException;
Object类中的clone方法是native方法,会调用系统级别函数,所以执行速度会很快
如果我们想要进行深度复制,即:无论属性是基本类型还是对象类型,都进行对象复制,看下面的设计方式
public class Brand implements Cloneable {
private String name;
private int age;
public Brand(String name, int age){
this.name = name;
this.age = age;
}
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;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Car implements Cloneable {
private int height;
private int weight;
private String country;
private Brand brand;
public Car(int height, int weight, String country, Brand brand){
this.height = height;
this.weight = weight;
this.country = country;
this.brand = brand;
}
public void getInfo(){
System.out.println("height : " + height);
System.out.println("weight : " + weight);
System.out.println("country : " + country);
System.out.println("brand name : " + brand.getName());
System.out.println("brand age : " + brand.getAge());
}
@Override
protected Object clone() throws CloneNotSupportedException {
Car c = (Car)super.clone();
if(brand != null){
Brand b = (Brand)brand.clone();
c.setBrand(b);
}
return c;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public Brand getBrand() {
return brand;
}
public void setBrand(Brand brand) {
this.brand = brand;
}
}
再次测试结果如下
BMW
1329552164
Benz
363771819
在进行深度复制时,如果对象属性依然包含对象属性,则每一层都需要进行深度复制,复制的层数可能会失控,对性能会有严重影响