原型模式定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象 原型模式类图如下: 我们来看下下面的代码 public class Brand { private String name; private int age; public
原型模式定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
原型模式类图如下:
我们来看下下面的代码
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
在进行深度复制时,如果对象属性依然包含对象属性,则每一层都需要进行深度复制,复制的层数可能会失控,对性能会有严重影响