原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。
主要解决:在运行期建立和删除原型。
何时使用:
1、当一个系统应该独立于它的产品创建,构成和表示时。
2、当要实例化的类是在运行时刻指定时,例如,通过动态装载。
3、为了避免创建一个与产品类层次平行的工厂类层次时。
4、当一个类的实例只能有几个不同状态组合中的一种时。建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。
如何解决:利用已有的一个原型对象,快速地生成和原型对象一样的实例。
关键代码: 1、实现克隆操作,在 JAVA 继承 Cloneable,重写 clone();在 .NET 中可以使用 Object 类的 MemberwiseClone() 方法来实现对象的浅拷贝或通过序列化的方式来实现深拷贝。 2、原型模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样要求这些"易变类"拥有稳定的接口。
优点: 1、性能提高。 2、逃避构造函数的约束。
缺点: 1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。 2、必须实现 Cloneable 接口。
原型模式通常适用于以下场景:
1.对象之间相同或相似,即只是个别的几个属性不同的时候。
2.对象的创建过程比较麻烦,但复制比较简单的时候。
原型模式包含以下主要角色:
抽象原型类:规定了具体原型对象必须实现的接口。
具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
访问类:使用具体原型类中的 clone() 方法来复制新的对象。
原型模式的克隆分为浅克隆和深克隆:
浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。
深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底。
Java 中的 Object 类提供了浅克隆的 clone() 方法,具体原型类只要实现 Cloneable 接口就可实现对象的浅克隆,这里的 Cloneable 接口就是抽象原型类。其代码如下:
浅复制:
/**
*
* @ClassName: Realizetype
* @Description: 具体原型类
* @author: ljx
* @date: 2019年1月3日 下午2:29:17
*/
public class Realizetype implements Cloneable{
public Realizetype() {
System.out.println("具体原型类创建");
}
public Object clone() throws CloneNotSupportedException{
System.out.println("具体原型类复制");
return (Realizetype)super.clone();
}
}
package prototype;
/**
*
* @ClassName: PrototypeTest1
* @Description: 测试类
* @author: ljx
* @date: 2019年1月3日 下午2:34:07
*/
public class PrototypeTest1 {
public static void main(String[] args) throws CloneNotSupportedException {
Realizetype r1 = new Realizetype();
//复制
Realizetype r2 = (Realizetype) r1.clone();
System.out.println("r1 == r2 ? "+(r1 == r2));
}
}
深复制:
/**
*
* @ClassName: Car
* @Description: 引用对象
* @author: ljx
* @date: 2019年1月3日 下午2:53:55
*/
public class Car implements Cloneable{
private int id;//车牌号码
/*(1)基本数据类型传值,是将栈中的类型传一个副本,对形参的修改不会影响实参;
(2)引用类型传引用,形参和实参指向同一个内存地址(同一个对象),是在堆中。所以对参数的修改会影响到实际的对象;
(3)String, Integer, Double等immutable的类型特殊处理,可以理解为传值,最后的操作不会修改实参对象。*/
private String brand;//车商标
public Car(int id,String brand){
this.id = id;
this.brand = brand;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public Car clone(){
Car car = null;
try {
car = (Car)super.clone();
} catch (Exception e) {
System.out.println(e.getMessage());
}
return car;
}
}
/**
*
* @ClassName: Prototype1
* @Description: 深克隆
* @author: ljx
* @date: 2019年1月3日 下午3:24:00
*/
public class Prototype1 implements Cloneable{
private int id;
private Car car;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
//重写克隆方法
public Object clone(){
Prototype1 prototype1 = null;
try {
prototype1 = (Prototype1) super.clone();
//深克隆
prototype1.setCar(this.car.clone());
} catch (Exception e) {
System.out.println(e.getMessage());
}
return prototype1;
}
}
/**
*
* @ClassName: Prototype1Test
* @Description: 深克隆测试
* @author: ljx
* @date: 2019年1月3日 下午3:25:18
*/
public class Prototype1Test {
public static void main(String[] args) {
Car car = new Car(8888, "法拉利");
Prototype1 prototype1 = new Prototype1();
prototype1.setId(8888888);
prototype1.setCar(car);
Prototype1 prototype12 = (Prototype1) prototype1.clone();
prototype12.setId(168168168);
prototype12.getCar().setBrand("玛莎拉蒂");
System.out.println(prototype1.getId());
System.out.println(prototype1.getCar().getId());
System.out.println(prototype1.getCar().getBrand());
System.out.println(prototype12.getId());
System.out.println(prototype12.getCar().getId());
System.out.println(prototype12.getCar().getBrand());
System.out.println(prototype1 == prototype12);
System.out.println(prototype1.getCar() == prototype12.getCar());
}
}
结果:
8888888
8888
法拉利
168168168
8888
玛莎拉蒂
false
false
......,欢迎指正