1、概述:通过给出一个原型对象来指明所要创建的对象的类型,利用这个原型对象来创建更多相似的统一类型的对象但又不是同一个对象(,世界上可能有千千万万个人,但你就是你,你是独一无二的,颜色不一样的花火,你是最棒的),因为如果直接创建对象的话,代价可能就会比较大,它属于创建型模式的一种,它提供了一种创建对象的最佳方法。
2、介绍:
意图:通过已创建的对象,我们知道要创建的对象类型,并且通过拷贝这些对象,就避免了直接创建对象的开销,节省了系统资源。原型模式是用于创建重复的对象,同时又保证性能,这种设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
解决问题:避免频繁的创建和删除资源消耗较大的对象,或者需要创建非常多的对象,比如数据库连接,细胞分裂等等
3、使用场景:
1、资源优化
2、初始化消耗资源较多,比如new对象,就包括硬件资源和数据等
3、对性能和安全要求较高的场景
4、需要短时间创建非常多的的对象
5、对于需要频繁进行新建和销毁操作的对象
4、内部实现的方式:因为类的初始化比较复杂,所以我们可以通过实现cloneable接口,实现了浅复制的功能,然后自己去对属性中的每个对象进行clone操作,就可以基本实现原型模式。
5、 模式的结构
原型模式包含以下主要角色。
- 抽象原型类:规定了具体原型对象必须实现的接口。
- 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
- 访问类:使用具体原型类中的 clone() 方法来复制新的对象。
接下来我们来看看代码:
抽象原型类:
public abstract class Shape implements Cloneable{
public String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public abstract void draw();
@Override
protected Object clone(){
Object o = null;
try {
o = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return o;
}
}
具体原型类:
public class Line extends Shape {
String id;
Body body;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Body getBody() {
return body;
}
public void setBody(Body body) {
this.body = body;
}
@Override
public Line clone(){
Line o = null;
o = (Line)super.clone();
o.body = (Body)body.clone();
return o;
}
public Line(String id, String name, Body body) {
super.setName(name);
this.id = id;
this.body = body;
}
@Override
public String toString() {
return "Line{" +
"id='" + id + '\'' +
", body=" + body +
", name='" + name + '\'' +
'}';
}
@Override
public void draw() {
System.out.println("i am a line");
}
}
原型属性对象
public class Body implements Cloneable{
Integer weight;
Integer height;
public Body(Integer weight, Integer height) {
this.weight = weight;
this.height = height;
}
public Integer getWeight() {
return weight;
}
public void setWeight(Integer weight) {
this.weight = weight;
}
public Integer getHeight() {
return height;
}
public void setHeight(Integer height) {
this.height = height;
}
@Override
public Object clone(){
Object o = null;
try {
o = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return o;
}
@Override
public String toString() {
return "Body{" +
"weight=" + weight +
", height=" + height +
'}';
}
}
测试方法
public static void main(String[] args) {
//用户操作鼠标过程
String id = "1";
String name = "张三";
Integer weight = 15;
Integer height = 25;
Body body = new Body(weight,height);
Line line1 = new Line(id,name,body);
//用户按下ctrl+c进行复制过程
Line line2 = line1.clone();
//用户按下ctrl+v进行粘贴过程
System.out.println("line1: " + line1);
System.out.println("line2: " + line2);
}
运行结果:
line1: Line{id='1', body=Body{weight=15, height=25}, name='张三'}
line2: Line{id='1', body=Body{weight=15, height=25}, name='张三'}
总结:原型模式就是利用已存在的对象,去创建更多相似却不相同对象的一个过程,因为创建对象的资源代价可能就比较大,所以我们就可以通过原型模式简单快速的创建大量对象,且资源消耗较低,
深复制和浅复制:
浅复制:仅仅克隆属性里面的基本类型的值
深复制:不仅仅克隆基本类型的值,而且还克隆属性里面的数组、集合和对象
大家看到这就已经够了,下面的是自己在写原型模式思考的一个问题,最后解决了心中的疑惑,其实也是个小问题,但是总感觉心里不踏实,就试着去搞清楚里面的套路。
题外话:Cloneable接口的clone方法,可以将父类,子类、子类的子类的属性都进行clone操作,即使只有父类重写了clone方法
父类
public class Parent implements Cloneable{
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Parent(String name) {
this.name = name;
}
@Override
protected Object clone(){
Object o = null;
try {
o = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return o;
}
}
子类
public class Son extends Parent{
private Integer age;
public Son(String name) {
super(name);
}
public Son(String name, Integer age) {
super(name);
this.age = age;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
//是否注释掉都毫无影响
@Override
public Object clone(){
Object o = null;
o = super.clone();
return o;
}
@Override
public String toString() {
return "Son{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
子类的子类
public class Sonson extends Son{
private Integer height;
public Sonson(String name) {
super(name);
}
public Sonson(String name, Integer age) {
super(name, age);
}
public Sonson(String name, Integer age, Integer height) {
super(name, age);
this.height = height;
}
public static void main(String[] args) {
Sonson son1 = new Sonson("zs",25,26);
Sonson son2 = (Sonson) son1.clone();
System.out.println(son1);
System.out.println(son2);
}
@Override
public String toString() {
return "Sonson{" +
"height=" + height +
", name='" + name + '\'' +
'}' + ", age: " + super.getAge();
}
}
输出结果
Sonson{height=26, name='zs'}, age: 25
Sonson{height=26, name='zs'}, age: 25
总结:实现了Cloneable接口的父类,那么他的子类,子类的子类,以及本身都会被克隆里面的属性。
这其实已经是题外话了,只不过是自己突然想到的一个问题,心存疑问,然后自己去尝试,探索出来的这么一个规律。