Java 设计模式・原型模式篇:从思想到代码实现
·
一、创建型模式
在面向对象的世界里,如何优雅地创建对象,是每一位开发者都会反复思考的问题。直接 new 一个对象固然简单,但当业务复杂度上升、依赖关系变得盘根错节时,这种方式就会让代码变得僵硬、难以维护。
创建型设计模式正是为了解决这一痛点而诞生的一套思想体系。它们将对象的创建与使用分离,通过封装、抽象和延迟实例化等手段,让代码更具灵活性、可扩展性和可测试性。
在 Java 开发中,创建型模式主要包含以下 5 种经典实现:
- 单例模式 (Singleton):确保一个类在整个应用中仅有一个实例,并提供一个全局访问点。Java 设计模式・单例模式篇:从思想到代码实现-CSDN博客
- 工厂方法模式 (Factory Method):定义一个创建对象的接口,让子类决定实例化哪一个类,将实例化逻辑延迟到子类。Java 设计模式・工厂模式篇:从思想到代码实现-CSDN博客
- 抽象工厂模式 (Abstract Factory):提供一个创建一系列相关或依赖对象的接口,而无需指定它们具体的类。Java 设计模式・工厂模式篇:从思想到代码实现-CSDN博客
- 建造者模式 (Builder):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。Java 设计模式・建造者模式篇:从思想到代码实现-CSDN博客
- 原型模式 (Prototype):用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。
二、原型模式
2.1 介绍
用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。
2.2 角色
-
抽象原型类:规定了具体原型对象必须实现的的 clone() 方法。
-
具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
三、克隆对比
| 特性 | 赋值(=) | 浅克隆 | 深克隆 |
|---|---|---|---|
| 是否创建新对象 | 否(共享同一个对象) | 是(仅外层对象新) | 是(所有层级对象都新) |
| 基本类型属性 | 共享(修改同步) | 复制值(修改不同步) | 复制值(修改不同步) |
| 引用类型属性 | 共享引用(修改同步) | 共享引用(修改同步) | 复制新对象(修改不同步) |
== 判断外层对象 |
true(同一地址) | false(新地址) | false(新地址) |
== 判断引用属性 |
true(同一地址) | true(同一地址) | false(新地址) |
对象的内存地址(堆内存中的物理地址)是在第一次通过 new/ 反射 / 克隆等方式创建时就永久确定的,后续永远无法修改;
四、赋值
4.1 代码
本文以中文为类名,方便理解
public class 用户 {
private String name;
private 地址 address;
public 用户() {
}
public 用户(String name, 地址 address) {
this.name = name;
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public 地址 getAddress() {
return address;
}
public void setAddress(地址 address) {
this.address = address;
}
@Override
public String toString() {
return "用户名:" + name + ",地址:" + address.getCity();
}
}
public class 地址 {
private String city;
public 地址() {
}
public 地址(String city) {
this.city = city;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
4.2 测试
public class 测试 {
public static void main(String[] args) {
地址 address = new 地址("上海");
用户 user1 = new 用户("张三" , address);
用户 user2 = user1;
check(user1 , user2);
user1.setName("李四");
check(user1 , user2);
address.setCity("北京");
check(user1 , user2);
}
public static void check(用户 user1 , 用户 user2) {
System.out.println(user1);
System.out.println(user2);
System.out.println(user1 == user2);
System.out.println(user1.getAddress() == user2.getAddress());
}
}
五、浅克隆
5.1 代码实现
Java中的Object类中提供了 clone() 方法来实现浅克隆。 Cloneable 接口是上面的类图中的抽象原型类,而实现了Cloneable接口的子实现类就是具体的原型类
如果没有实现该接口直接调用该方法会报错,因为此方法被定义为 protected native Object clone() throws CloneNotSupportedException
protected 方法的访问规则是:
- 只能在同一个包内的类,或者子类中被访问。
- 如果你在一个不相关的类中直接调用
obj.clone(),就会触发这个编译
所以要重写此方法,并把访问范围改成public
public class 用户 implements Cloneable{
private String name;
private 地址 address;
public 用户() {
}
public 用户(String name, 地址 address) {
this.name = name;
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public 地址 getAddress() {
return address;
}
public void setAddress(地址 address) {
this.address = address;
}
@Override
public String toString() {
return "用户名:" + name + ",地址:" + address.getCity();
}
@Override
public 用户 clone() {
try {
return (用户) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
5.2 测试
public class 测试 {
public static void main(String[] args) {
地址 address = new 地址("上海");
用户 user1 = new 用户("张三" , address);
用户 user2 = user1.clone();
check(user1 , user2);
user1.setName("李四");
check(user1 , user2);
address.setCity("北京");
check(user1 , user2);
}
public static void check(用户 user1 , 用户 user2) {
System.out.println(user1);
System.out.println(user2);
System.out.println(user1 == user2);
System.out.println(user1.getAddress() == user2.getAddress());
}
}
六、深克隆
6.1 手动递归重写 clone () 方法
public class 用户 implements Cloneable{
private String name;
private 地址 address;
public 用户() {
}
public 用户(String name, 地址 address) {
this.name = name;
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public 地址 getAddress() {
return address;
}
public void setAddress(地址 address) {
this.address = address;
}
@Override
public String toString() {
return "用户名:" + name + ",地址:" + address.getCity();
}
@Override
public 用户 clone() {
try {
用户 user = (用户) super.clone();
user.address = address.clone();
return user;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
public class 地址 implements Cloneable{
private String city;
public 地址() {
}
public 地址(String city) {
this.city = city;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public 地址 clone() {
try {
return (地址) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
测试代码不变
6.2 给所有类加上Serializable
这种不需要一个一个去重写方法了,只需要把涉及的类都标记可序列化,只需要在需要克隆的方法上添加深克隆的方法
public class 用户 implements Serializable {
private String name;
private 地址 address;
public 用户() {
}
public 用户(String name, 地址 address) {
this.name = name;
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public 地址 getAddress() {
return address;
}
public void setAddress(地址 address) {
this.address = address;
}
@Override
public String toString() {
return "用户名:" + name + ",地址:" + address.getCity();
}
public 用户 deepClone() throws IOException, ClassNotFoundException {
// 1. 将对象写入字节流
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
// 2. 从字节流读取新对象
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (用户) ois.readObject();
}
}
public class 地址 implements Serializable {
private String city;
public 地址() {
}
public 地址(String city) {
this.city = city;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
测试
public class 测试 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
地址 address = new 地址("上海");
用户 user1 = new 用户("张三" , address);
用户 user2 = user1.deepClone();
check(user1 , user2);
user1.setName("李四");
check(user1 , user2);
address.setCity("北京");
check(user1 , user2);
}
public static void check(用户 user1 , 用户 user2) {
System.out.println(user1);
System.out.println(user2);
System.out.println(user1 == user2);
System.out.println(user1.getAddress() == user2.getAddress());
}
}
七、其他相关设计模式
更多推荐



所有评论(0)