设计模式之原型模式
-
- [🧐1. 概念](#🧐1. 概念)
- [🎯2. 原型模式的作用](#🎯2. 原型模式的作用)
- [📦3. 实现](#📦3. 实现)
-
- [1. 定义原型接口](#1. 定义原型接口)
- [2. 定义具体的原型类](#2. 定义具体的原型类)
- [3. 定义客户端](#3. 定义客户端)
- [4. 结果](#4. 结果)
- [📰 4. 应用场景](#📰 4. 应用场景)
- [🔍5. 深拷贝和浅拷贝](#🔍5. 深拷贝和浅拷贝)
在面向对象编程中,设计模式是一种通用的解决方案,用于解决软件设计过程中常见的问题。原型模式(Prototype Pattern
)作为创建型设计模式的一员,旨在通过复制现有对象来创建新对象,而非通过常规的构造函数。这种模式不仅简化了对象的创建过程,而且在特定情况下还能显著提升性能。
🧐1. 概念
原型模式允许客户端复制一个已存在的对象,而不是通过常规的构造器创建一个新的实例。这种方法的主要优点在于,如果对象的创建成本很高(例如,初始化过程复杂、需要从数据库加载大量数据等),那么通过复制现有对象的方式可以有效减少资源消耗,提高系统的整体性能。
Prototype
(抽象原型类):它是声明克隆方法的接口,是所有具体原型类的公共父类,可以是抽象类也可以是接口,甚至还可以是具体实现类。ConcretePrototype
(具体原型类):它实现在抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。Client
(客户端类 ):通过调用clone()
方法来创建新的对象,并展示了原始对象与克隆对象之间的独立性。
🎯2. 原型模式的作用
- 简化对象创建:通过复制现有的对象,可以避免复杂的构造过程,尤其是当对象的初始化需要进行大量的计算或资源分配时。
- 提高性能:对于那些创建成本高得对象,使用原型模式可以显著减少内存消耗和处理时间。
- 增加系统灵活性:通过修改原型对象得属性,可以快速生成不同状态的新对象,这比通过继承来实现更加灵活。
📦3. 实现
实现原型模式的核心在于定义一个原型接口,该接口包含一个用于复制自身的克隆方法。在不同的编程语言中,实现方式可能会有所不同,但基本思路是一致的。
1. 定义原型接口
java
public interface Prototype extends Cloneable {
Prototype clone();
}
此处的
Cloneable
接口是一个标记接口,表示该类可以被克隆。类似的标记接口还有
Serializable
:用于标记一个类的对象可以被序列化和反序列化。RandomAccess
:用于标记一个列表支持随机访问,即通过索引直接访问元素吗,而不是遍历。Remote
:用于远程方法调用,标记一个类支持远程方法调用。
2. 定义具体的原型类
java
public class ConcretePrototype implements Prototype {
private String attribute;
public ConcretePrototype(String attribute) {
this.attribute = attribute;
}
@Override
public Prototype clone() {
try {
return (ConcretePrototype) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError("Cannot clone.", e);
}
}
public String getAttribute() {
return attribute;
}
public void setAttribute(String attribute) {
this.attribute = attribute;
}
}
3. 定义客户端
java
public class Client {
public static void main(String[] args) {
ConcretePrototype prototype = new ConcretePrototype("Initial Value");
ConcretePrototype clonedPrototype = (ConcretePrototype) prototype.clone();
System.out.println("Original Attribute: " + prototype.getAttribute());
System.out.println("Cloned Attribute: " + clonedPrototype.getAttribute());
clonedPrototype.setAttribute("Modified Value");
System.out.println("After Modification:");
System.out.println("Original Attribute: " + prototype.getAttribute());
System.out.println("Cloned Attribute: " + clonedPrototype.getAttribute());
}
}
4. 结果
在这个示例中,ConcretePrototype
类实现了 Prototype
接口,并提供了具体的 clone()
方法实现。客户端代码展示了如何通过调用 clone()
方法来创建新的对象,并展示了原始对象与克隆对象之间的独立性。
📰 4. 应用场景
- 对象创建成本高:当对象的创建对象过程非常复杂或耗时,例如需要从网络加载数据、执行复炸的算法等,使用原型模式可以通过复制现有对象来节省时间和资源。
- 避免复杂的构造过程:如果对象的创建涉及到复杂的初始化步骤,使用原型模式可以简化这些步骤,通过复制已有对象来快速生成新的对象。
- 动态对象创建:在某些情况下,程序需要根据用户的输入或其他条件动态地创建对象。原型模式提供了一种灵活的方式来满足这种需求,无需预先定义所有的对象类型。
- 实际项目当中使用原型模式,实现
Cloneable
接口并重写clone()
方法。或者编写自己的特有的原型类Prototype
,然后实现Prototype
的clone()
方法。
🔍5. 深拷贝和浅拷贝
在讨论原型模式时,深拷贝 和浅拷贝 是一个不可忽视的话题。浅拷贝 只会复制对象的基本数据类型和其他对象的引用,而不会递归地复制引用对象本身。相反,深拷贝会递归地复制整个对象树,确保新对象与原有对象完全独立。
在 Java
中, 默认的 clone()
方法实现的是浅拷贝。如果需要实现深拷贝,通常需要手动编写代码来处理对象中的引用类型属性。例如,可以使用序列化和反序列化的方式来实现深拷贝:
java
public class DeepClonePrototype implements Cloneable, Serializable {
private transient String attribute; // 使用 transient 修饰符表示不参与序列化
public DeepClonePrototype(String attribute) {
this.attribute = attribute;
}
public String getAttribute() {
return this.attribute;
}
public void setAttribute(String attribute) {
this.attribute = attribute;
}
@Override
protected DeepClonePrototype clone() {
try {
// 使用序列化和反序列化实现深拷贝
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteOut);
out.writeObject(this);
ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
ObjectInputStream in = new ObjectInputStream(byteIn);
return (DeepClonePrototype) in.readObject();
} catch (IOException | ClassNotFoundException e) {
throw new AssertionError("Cannot clone.", e);
}
}
}