今天520情人节,你确定不学一下「情话设计模式」?
码个蛋
共 7775字,需浏览 16分钟
·
2021-05-23 11:37
前言
目录
原型模式简介
原型模式的应用场景
原型模式的结构与实现
原型模式的优缺点
原型模式的应用实例
思维导图
原型模式在JDK源码中的应用
原型模式简介
原型模式的应用场景
原型模式通常适用于以下场景。
对象之间相同或相似,即只是个别的几个属性不同的时候。
创建对象成本较大,例如初始化时间长,占用CPU太多,或者占用网络资源太多等,需要优化资源。
创建一个对象需要繁琐的数据准备或访问权限等,需要提高性能或者提高安全性。
系统中大量使用该类对象,且各个调用者都需要给它的属性重新赋值。
原型模式的结构与实现
1.模式的结构
抽象原型类:规定了具体原型对象必须实现的接口。 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。 访问类:使用具体原型类中的 clone() 方法来复制新的对象。
实现Cloneable接口。在java语言有一个Cloneable接口,它的作用只有一个,就是在运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法。在java虚拟机中,只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出CloneNotSupportedException异常。 重写Object类中的clone方法。Java中,所有类的父类都是Object类,Object类中有一个clone方法,作用是返回对象的一个拷贝,但是其作用域protected类型的,一般的类无法调用,因此,Prototype类需要将clone方法的作用域修改为public类型。
2.模式的实现
浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
Java中的 Object 类提供了浅克隆的 clone() 方法,具体原型类只要实现 Cloneable 接口就可实现对象的浅克隆,这里的 Cloneable 接口就是抽象原型类。其代码如下:
//具体原型类
class Realizetype implements Cloneable {
Realizetype() {
System.out.println("具体原型创建成功!");
}
public Object clone() throws CloneNotSupportedException {
System.out.println("具体原型复制成功!");
return (Realizetype) super.clone();
}
}
//原型模式的测试类
public class PrototypeTest {
public static void main(String[] args) throws CloneNotSupportedException {
Realizetype obj1 = new Realizetype();
Realizetype obj2 = (Realizetype) obj1.clone();
System.out.println("obj1==obj2?" + (obj1 == obj2));
}
}
具体原型创建成功!
具体原型复制成功!
obj1==obj2?false
原型模式的优缺点
原型模式的优点:
Java 自带的原型模式基于内存二进制流的复制,在性能上比直接 new 一个对象更加优良。因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。 简化对象的创建,使得创建对象就像我们在编辑文档时的复制粘贴一样简单。可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,并将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。
原型模式的缺点:
需要为每一个类都配置一个 clone 方法 clone 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。 当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。因此,深克隆、浅克隆需要运用得当。
原型模式的应用实例
图 孙悟空生成器的结构图
import java.awt.*;
import javax.swing.*;
class SunWukong extends JPanel implements Cloneable {
private static final long serialVersionUID = 5543049531872119328L;
public SunWukong() {
JLabel l1 = new JLabel(new ImageIcon("src/Wukong.jpg"));
this.add(l1);
}
public Object clone() {
SunWukong w = null;
try {
w = (SunWukong) super.clone();
} catch (CloneNotSupportedException e) {
System.out.println("拷贝悟空失败!");
}
return w;
}
}
public class ProtoTypeWukong {
public static void main(String[] args) {
JFrame jf = new JFrame("原型模式测试");
jf.setLayout(new GridLayout(1, 2));
Container contentPane = jf.getContentPane();
SunWukong obj1 = new SunWukong();
contentPane.add(obj1);
SunWukong obj2 = (SunWukong) obj1.clone();
contentPane.add(obj2);
jf.pack();
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
思维导图
原型模式在JDK源码中的应用
public interface Cloneable {
}
public Object clone() {
try {
@SuppressWarnings("unchecked")
ArrayList<E> v = (ArrayList<E>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
public class ConcretePrototype implements Cloneable,Serializable {
public ConcretePrototype deepCloneHobbies(){
try {
ConcretePrototype result = (ConcretePrototype) super.clone();
result.hobbies = (List) ((ArrayList) result.hobbies).clone();
return result;
}catch (CloneNotSupportedException){
return null;
}
}
...
}
public static void main(String[] args) {
...
//复制原型对象
ConcretePrototype cloneType = prototype.deepCloneHobbies();
...
}
原型对象:ConcretePrototype{age=18,name='C语言中文网',hobbies=[书法, 美术]}
克隆对象:ConcretePrototype{age=18,name='C语言中文网',hobbies=[书法, 美术, 技术控]}
码个蛋专属活动:打卡入口
为什么要做这个活动?
关注「码个蛋」,一起打卡成长
评论