好记忆不如烂笔头,能记下点东西,就记下点,有时间拿出来看看,也会发觉不一样的感受.
原型模式模式是java中很常见的设计模式,如下将好好讲解下java设计抽象工厂方法模式相关的知识。本文还是将从:它的前世今生;使用场景;注意事项;代码样例等四个方面,详细阐述下原型模式的细节内容。
一、原型模式的前世今生
-
起源与发展
-
原型模式是一种创建型设计模式,最早在设计模式的经典著作《设计模式:可复用面向对象软件的基础》(GoF)中被提出。在软件开发过程中,人们发现有时需要创建与现有对象相同或相似的对象,直接复制已有对象比重新创建更高效,原型模式便应运而生。
-
随着面向对象编程的发展,原型模式在不同编程语言中得到了广泛应用和演变。在 Java 中,通过克隆机制(Cloneable 接口和 clone() 方法)为实现原型模式提供了基础支持。
-
-
基本思想
-
原型模式允许一个对象通过自身复制来创建新的对象实例,而不是通过传统的构造函数创建。它基于已经存在的对象,快速构建一个与之具有相同或相似属性和行为的新对象,减少因创建新对象带来的资源消耗和时间成本。
-
-
与其他模式的关系
-
与工厂模式:工厂模式侧重于通过工厂类创建对象,而原型模式则通过对象自身复制来创建新对象。原型模式在某种程度上可以看作是工厂模式的特殊实现方式。
-
与单例模式:单例模式保证一个类只有一个实例,而原型模式可以创建多个具有相同属性的实例,但它们的属性可以独立修改。
-
二、原型模式的使用场景
-
性能优化场景
-
当创建新对象比复制现有对象成本更高时,如需要进行复杂的初始化操作或涉及大量资源分配(如文件读取、数据库连接等),使用原型模式可以通过复制已有对象来快速获取新对象,提高性能。例如,在一个包含大量图像对象的应用中,若创建图像对象需要从磁盘读取文件并进行解码等操作,而某些图像对象具有相似属性,此时可使用原型模式,先创建一个基础图像对象,其他图像对象通过复制该基础对象并适当修改部分属性来实现。
-
-
复杂对象创建场景
-
当一个对象的创建过程较为复杂,涉及多个步骤或依赖于其他对象的创建时,使用原型模式可以简化对象的创建过程。比如,在一个游戏开发场景中,创建一个游戏角色对象可能需要设置角色的属性、装备、技能等多个方面,并且这些属性之间可能存在相互依赖关系。此时,可以先创建一个典型角色对象作为原型,其他角色对象通过复制原型对象并在需要的地方进行修改来实现。
-
-
动态加载或运行时决定对象类型场景
-
在某些情况下,系统在运行时才确定需要创建哪种类型的对象,且这些对象具有相似的结构和行为。原型模式可以根据已有的原型对象,动态地创建出符合要求的新对象。例如,一个文档编辑软件中,支持多种文档格式(如文本文档、表格文档、图片文档等),每种文档对应一个对象类。在打开文档时,系统根据文档的实际类型(运行时确定)找到对应的原型对象,通过克隆原型对象来创建新的文档对象进行编辑。
-
三、原型模式使用的注意事项
-
实现 Cloneable 接口
-
在 Java 中,若想实现原型模式,类需要实现 Cloneable 接口,该接口是一个标记接口,没有方法需要实现。实现此接口的目的是让对象具备被克隆的能力,否则在调用 clone() 方法时会抛出 CloneNotSupportedException 异常。
-
-
重写 clone() 方法
-
虽然 Object 类中提供了 clone() 方法,但默认实现是浅拷贝。如果对象包含对其他对象的引用,仅复制引用地址,而不会复制引用对象本身。因此,在实际应用中,若需要深拷贝,需要根据具体需求重写 clone() 方法,对对象中的引用类型成员变量进行深度复制。例如,对于一个包含集合对象或自定义对象成员变量的类,需要在克隆过程中重新创建这些引用对象,以确保新对象与原对象在内存上完全独立。
-
-
对象的独立性
-
即使通过原型模式创建了新对象,新对象与原对象在内存上是相互独立的。但在浅拷贝情况下,它们可能共享一些引用对象。因此,在修改新对象或原对象的属性时,需要注意对共享对象的影响,避免出现数据不一致的问题。例如,若两个对象共享一个列表对象,修改其中一个对象中列表的内容会影响另一个对象。
-
-
线程安全问题
-
如果在多线程环境下使用原型模式,且原型对象可能被多个线程同时访问和克隆,需要考虑线程安全问题。可以通过将克隆方法设置为同步方法(synchronized)或采用其他线程安全机制来确保在并发情况下对象克隆的正确性。

-
四、原型模式的代码样例
// 原型接口,声明克隆方法
public interface Prototype {
Prototype clone();
}
// 具体原型类,实现原型接口
public class ConcretePrototype implements Prototype, Cloneable {
private String name;
// 引用类型成员变量,用于演示深拷贝
private List<String> list;
public ConcretePrototype(String name) {
this.name = name;
this.list = new ArrayList<>();
}
@Override
public ConcretePrototype clone() {
try {
// 调用 Object 的 clone() 方法进行浅拷贝
ConcretePrototype cloneObj = (ConcretePrototype) super.clone();
// 对引用类型成员变量进行深拷贝,重新创建一个新的列表对象并复制内容
cloneObj.list = new ArrayList<>(this.list);
return cloneObj;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
public void addListItem(String item) {
list.add(item);
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
ConcretePrototype prototype1 = new ConcretePrototype("Prototype1");
prototype1.addListItem("Item1");
prototype1.addListItem("Item2");
// 克隆原型对象
ConcretePrototype prototype2 = prototype1.clone();
System.out.println("prototype1 name: " + prototype1.getName());
System.out.println("prototype1 list: " + prototype1.getList());
System.out.println("prototype2 name: " + prototype2.getName());
System.out.println("prototype2 list: " + prototype2.getList());
// 修改克隆后的对象
prototype2.setName("Prototype2");
prototype2.addListItem("Item3");
System.out.println("\nAfter modification:");
System.out.println("prototype1 name: " + prototype1.getName());
System.out.println("prototype1 list: " + prototype1.getList());
System.out.println("prototype2 name: " + prototype2.getName());
System.out.println("prototype2 list: " + prototype2.getList());
}
}
运行结果示例:
prototype1 name: Prototype1
prototype1 list: [Item1, Item2]
prototype2 name: Prototype1
prototype2 list: [Item1, Item2]
After modification:
prototype1 name: Prototype1
prototype1 list: [Item1, Item2]
prototype2 name: Prototype2
prototype2 list: [Item1, Item2, Item3]
通过这个示例可以看出,原型模式成功创建了对象的副本,并且在克隆过程中对引用类型成员变量进行了深拷贝处理,使得修改克隆后的对象不会影响原对象。

1436

被折叠的 条评论
为什么被折叠?



