原型模式 (Prototype Pattern) 类似于ctrl+c然后ctrl+v,用于复制对象,而非创建,因为创建对象相对于复制,更消耗资源一些,而且不能获得对象在运行时的状态。但原型模式会使得访问权限失效,因为是直接从内存中拷贝对象,所以要注意使用的范围。它的使用场景也和生活中的拷贝类似:
- 当需要大量相同或者相似的对象时
- 当需要更多运行时的对象状态,而非初始的、干净的、空的对象状态时
- 当类的初始化会消耗大量资源时
- 当对象的创建要求复杂的数据准备、各类权限时
- 当需要解耦框架和产生的实例时,即不使用类名来创建一些实例
原型模式的结构:
- 抽象原型类 (Abstract Prototype):规定了具体原型对象必须实现的接口,提供解耦功能,它继承或实现
Cloneable
接口(仅仅只起标识作用,同Serializable
接口,不继承而使用clone
方法会导致CloneNotSupportedException
异常),并重写Object
类的clone
方法; - 具体原型类 (Concrete Prototype):实现抽象原型类,是被克隆的目标类;
- 调用者 (Invoker):具体原型类的调用者。
原型模式是有浅拷贝 (Shallow Copy) 和深拷贝 (Deep Copy) 之分的。浅拷贝指的是对于八种基本数据类型的拷贝,Object
类的clone
方法的默认实现就是浅拷贝;深拷贝指的是针对除了八种基本数据类型以外的类型的拷贝,如数组、列表、集合。需要我们自己来写代码实现深拷贝。
/**
* 抽象原型类
* @author 青青橙
*
*/
public interface AbstractPrototype extends Cloneable {
void printShapeType();
Object clone();
}
import java.util.HashMap;
/**
* 具体原型类
* @author 青青橙
*
*/
public class ConcretePrototypeCircle implements AbstractPrototype {
private String shapeName;
private HashMap<Integer, String> info;
private Circle circle;
/*
* get、set和toString方法
*/
public ConcretePrototypeCircle(String shapeName, HashMap<Integer, String> info, Circle circle) {
super();
this.shapeName = shapeName;
this.info = info;
this.circle = circle;
}
@SuppressWarnings({"unchecked"})
@Override
public Object clone() {
ConcretePrototypeCircle concretePrototypeCircle = null;
try {
// 对基本类型进行浅克隆
concretePrototypeCircle= (ConcretePrototypeCircle)super.clone();
// 对每个复杂类型进行单独克隆,需要先在该复杂类型的类中继承Cloneable接口,重写clone()方法或者使用序列化进行克隆
// 这里HashMap已经继承Cloneable接口,且重写了clone方法,因此可以直接使用
concretePrototypeCircle.info = (HashMap<Integer, String>)this.info.clone();
// 对自定义对象进行深克隆,同复杂类型
concretePrototypeCircle.circle = (Circle)this.circle.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return concretePrototype;
}
@Override
public void printShapeType() {
System.out.println(Circle.CIRCLE);
}
}
/**
* 自定义复杂对象javabean
* 需要实现Cloneable接口,重写clone方法
* @author 青青橙
*
*/
public class Circle implements Cloneable {
public static final String CIRCLE = "Circle";
@Override
protected Object clone() throws CloneNotSupportedException {
return (Circle)super.clone();
}
@Override
public String toString() {
return CIRCLE;
}
}
import java.util.HashMap;
/**
* 普通原型模式调用者
* @author 青青橙
*
*/
public class Invoker {
public static void main(String[] args) {
HashMap<Integer, String> info = new HashMap<Integer, String>(16);
info.put(1, "半径为2");
AbstractPrototype abstractPrototype = new ConcretePrototypeCircle("圆形", info, new Circle());
System.out.println(abstractPrototype);
AbstractPrototype clone = (ConcretePrototypeCircle)abstractPrototype.clone();
System.out.println(clone);
}
}
运行调用者,输出结果为:
ConcretePrototype [shapeName=圆形, info={1=半径为2}, shapeType=Circle]
ConcretePrototype [shapeName=圆形, info={1=半径为2}, shapeType=Circle]
两对象内容相同,当然,内存地址是不同的。去掉剧体原型类中的toString方法,输出内存地址即可验证。当然这里的Circle
类完全可以不要,只是为了模拟自定义对象的克隆才强行写的。
这就是基本的原型模式使用方法,还可以为原型模式中加入原型管理器 (PrototypeManager),扩展原型模式。该类用HashMap
保存多种原型,调用者可以通过原型管理器提供的get(String id)
方法从中获取不同原型的复制。
再创建一个具体原型类,来使得原型管理器能放入多种原型:
import java.util.HashMap;
/**
* 具体原型类
* @author 青青橙
*
*/
public class ConcretePrototypeSquare implements AbstractPrototype {
private String shapeName;
private HashMap<Integer, String> info;
private Square square;
/*
* get、set和toString方法
*/
public ConcretePrototypeSquare(String shapeName, HashMap<Integer, String> info, Square square) {
super();
this.shapeName = shapeName;
this.info = info;
this.square = square;
}
@SuppressWarnings({"unchecked"})
@Override
public Object clone() {
ConcretePrototypeSquare concretePrototypeSquare = null;
try {
// 对基本类型进行浅克隆
concretePrototypeSquare = (ConcretePrototypeSquare)super.clone();
// 对每个复杂类型进行单独克隆,需要先在该复杂类型的类中继承Cloneable接口,重写clone()方法或者使用序列化进行克隆
// 这里HashMap已经继承Cloneable接口,且重写了clone方法,因此可以直接使用
concretePrototypeSquare.info = (HashMap<Integer, String>)this.info.clone();
// 对自定义对象进行深克隆,同复杂类型
concretePrototypeSquare.square = (Square)this.square.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return concretePrototypeSquare;
}
@Override
public void printShapeType() {
System.out.println(Square.SQUARE);
}
}
/**
* 自定义复杂对象javabean
* @author 青青橙
*
*/
public class Square implements Cloneable {
public static final String SQUARE = "Square";
@Override
protected Object clone() throws CloneNotSupportedException {
return (Square)super.clone();
}
@Override
public String toString() {
return SQUARE;
}
}
原型管理器:
import java.util.HashMap;
/**
* 原型管理器:存放多种原型,返回不同原型的复制
* @author 青青橙
*
*/
public class PrototypeManager {
private HashMap<String, AbstractPrototype> prototypeMap = null;
public PrototypeManager() {
super();
prototypeMap = new HashMap<>(16);
HashMap<Integer, String> info1 = new HashMap<Integer, String>(16);
info1.put(1, "半径为3");
prototypeMap.put("圆", new ConcretePrototypeCircle("圆形", info1, new Circle()));
HashMap<Integer, String> info2 = new HashMap<Integer, String>(16);
info2.put(1, "边长为3");
prototypeMap.put("方", new ConcretePrototypeSquare("方形", info2, new Square()));
}
public void addShape(String key, AbstractPrototype abstractPrototype) {
prototypeMap.put(key, abstractPrototype);
}
public AbstractPrototype getShape(String key) {
AbstractPrototype abstractPrototype = prototypeMap.get(key);
return (AbstractPrototype)abstractPrototype.clone();
}
}
调用者:
/**
* 扩展原型模式调用者
* @author 青青橙
*
*/
public class Invoker2 {
public static void main(String[] args) {
PrototypeManager prototypeManager = new PrototypeManager();
AbstractPrototype circle = prototypeManager.getShape("圆");
System.out.println(circle);
AbstractPrototype square = prototypeManager.getShape("方");
System.out.println(square);
}
}
运行调用者,输出如下:
ConcretePrototypeCircle [shapeName=圆形, info={1=半径为3}, shapeType=Circle]
ConcretePrototypeSquare [shapeName=方形, info={1=边长为3}, shapeType=Square]
获取到两种原型的克隆。