1.定义
通过复制现有的实例来创建新的实例,同时又能保证较高性能。
2.使用场景及设计
2.1.使用场景
创建对象耗时又耗费资源时候可以使用。
2.2.设计
使用原型模式克隆对象时候又分为浅拷贝和深拷贝。
- 浅拷贝
只拷贝目标对象,不拷贝对象的成员属性。 - 深拷贝
拷贝目标对象,并且拷贝对象的成员属性
3.测试代码
此处测试浅拷贝,入口代码
package com.glt.designpattern.prototype;
public class InitMain {
public static void main(String[] args) {
ShapeCache.loadShape();
Shape circle = ShapeCache.getShape("1");
circle.draw();
System.out.println("circle hashcode=" + circle.hashCode());
System.out.println("circle.type hashcode=" + circle.getType().hashCode());
Shape circle2 = ShapeCache.getShape("1");
circle2.draw();
System.out.println("circle2 hashcode=" + circle2.hashCode());
System.out.println("circle2.type hashcode=" + circle2.getType().hashCode());
Shape square = ShapeCache.getShape("2");
square.draw();
System.out.println("square hashcode=" + square.hashCode());
System.out.println("square.type hashcode=" + square.getType().hashCode());
Shape square2 = ShapeCache.getShape("2");
square2.draw();
System.out.println("square2 hashcode=" + square2.hashCode());
System.out.println("square2.type hashcode=" + square2.getType().hashCode());
}
}
抽象类继承Cloneable接口
package com.glt.designpattern.prototype;
public abstract class Shape implements Cloneable {
private String id;
private String type;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public abstract void draw();
@Override
protected Object clone(){
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
圆形实现类继承抽象类
package com.glt.designpattern.prototype;
public class Circle extends Shape {
public Circle(){
this.setType("circle");
}
@Override
public void draw() {
System.out.println("this is 圆形");
}
}
正方形实现类继承抽象类
package com.glt.designpattern.prototype;
public class Square extends Shape {
public Square(){
this.setType("square");
}
@Override
public void draw() {
System.out.println("this is 正方形");
}
}
创建类生产原型对象
package com.glt.designpattern.prototype;
import java.util.Hashtable;
public class ShapeCache {
private static Hashtable<String,Shape> map = new Hashtable<>();
public static void loadShape(){
Circle circle = new Circle();
circle.setId("1");
map.put(circle.getId(),circle);
Square square = new Square();
square.setId("2");
map.put(square.getId(),square);
}
public static Shape getShape(String id){
Shape shape = map.get(id);
return (Shape) shape.clone();
}
}
输出如下:
this is 圆形
circle hashcode=41359092
circle.type hashcode=-1360216880
this is 圆形
circle2 hashcode=149928006
circle2.type hashcode=-1360216880
this is 正方形
square hashcode=713338599
square.type hashcode=-894674659
this is 正方形
square2 hashcode=168423058
square2.type hashcode=-894674659
Process finished with exit code 0
如上所示,拷贝出来的目标对象的hashcode是不一样的,但是拷贝出来的同一原型的成员属性的hashcode的一样的,即使用的是同一引用。
4.总结
原型模式中的浅拷贝和深拷贝的区别在于有没有拷贝其成员属性。
想要实现深拷贝只需要在实现的clone()方法中将目标对象的成员属性同时拷贝即可,也可以根据业务选择性拷贝成员属性。
原型模式优点:
- 能够减少同类对象创建的资源消耗,提高性能。
- 目标对象过于复杂的情况,使用原型模式比手工创建对象方便快捷。
缺点:
- 有循环结构的类对象,使用原型模式会遇到很大困难。
- 必须要继承java的Cloneable接口,实现clone()方法。
参考资料:
菜鸟教程
《Head Firsh 设计模式》(中文版)