目录
- 一、 啥是原型模式?
- 二、 为什么要用原型模式?
- 三、 原型模式怎么实现?
- 四、 原型模式的应用场景
- 五、 原型模式的优点和缺点
- 六、 总结
我的其他文章也讲解的比较有趣,如果喜欢博主的讲解方式,可以多多支持一下,感谢!
了解工厂方法模式请看: (三)趣学设计模式 之 抽象工厂模式!
这篇文章带你详细认识一下设计模式中的原型模式
原型模式,说白了,就是“山寨”! 你有一个宝贝,不想自己辛辛苦苦再做一个,就找个复印机(克隆方法),咔嚓一下,复制一个一模一样的出来!
用原型模式,好处多多:
原型模式主要有两种“山寨”方法:
实现原型模式的关键点
1.浅拷贝(Shallow Copy):只复制表面!
浅拷贝就像复印身份证 ,你复印了一张身份证,上面的名字、地址都一样,但是里面的芯片还是原来的那个。如果原来的身份证信息变了,复印件也会跟着变!
// 1. 定义原型接口 (Cloneable 是 Java 内置的接口)
interface Prototype extends Cloneable {
Prototype clone(); // 克隆方法
}
// 2. 定义具体原型类
class Sheep implements Prototype {
private String name;
private int age;
private Address address; // 引用类型属性
public Sheep(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Address getAddress() {
return address;
}
public void setAddress(String city) {
this.address.setCity(city);
}
@Override
public Sheep clone() {
try {
// 浅拷贝:直接调用 Object 类的 clone() 方法
return (Sheep) super.clone();
} catch (CloneNotSupportedException e) {
System.out.println("克隆失败! ");
return null;
}
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
", address=" + address +
'}';
}
}
// 地址类 (引用类型)
class Address {
private String city;
public Address(String city) {
this.city = city;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public String toString() {
return "Address{" +
"city='" + city + '\'' +
'}';
}
}
// 3. 客户端使用
public class Client {
public static void main(String[] args) {
// 创建原型对象
Address address = new Address("北京");
Sheep originalSheep = new Sheep("多莉", 3, address);
// 克隆原型对象
Sheep clonedSheep = originalSheep.clone();
// 打印原始对象和克隆对象
System.out.println("原始羊: " + originalSheep);
System.out.println("克隆羊: " + clonedSheep);
// 修改原始对象的引用类型属性
originalSheep.setAddress("上海");
// 再次打印原始对象和克隆对象
System.out.println("修改后的原始羊: " + originalSheep);
System.out.println("修改后的克隆羊: " + clonedSheep);
}
}
代码解释:
Prototype
:原型接口,定义了克隆方法。Sheep
:具体原型类,实现了 Prototype
接口,表示羊。clone()
:克隆方法,用于创建对象的副本。Address
:地址类,作为 Sheep
类的引用类型属性。输出结果:
原始羊: Sheep{name='多莉', age=3, address=Address{city='北京'}}
克隆羊: Sheep{name='多莉', age=3, address=Address{city='北京'}}
修改后的原始羊: Sheep{name='多莉', age=3, address=Address{city='上海'}}
修改后的克隆羊: Sheep{name='多莉', age=3, address=Address{city='上海'}}
分析:
可以看到,修改原始羊的地址后,克隆羊的地址也跟着改变了!这是因为浅拷贝只复制了地址的“指针”,原始羊和克隆羊指向的是同一个地址,所以一个变了,另一个也跟着变!
2. 深拷贝(Deep Copy):彻底复制!
深拷贝就像克隆一只完整的羊 ,你克隆了一只羊,它有自己的名字、年龄和地址,和原来的羊完全没有关系。即使原来的羊死了,克隆羊还是活蹦乱跳的!
import java.io.*;
class Sheep implements Prototype, Serializable { // 注意实现 Serializable 接口
private String name;
private int age;
private Address address;
public Sheep(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public Sheep clone() {
try {
// 使用序列化和反序列化实现深拷贝
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (Sheep) ois.readObject();
} catch (Exception e) {
System.out.println("克隆失败! ");
return null;
}
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
", address=" + address +
'}';
}
}
class Address implements Serializable { // 注意实现 Serializable 接口
private String city;
public Address(String city) {
this.city = city;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public String toString() {
return "Address{" +
"city='" + city + '\'' +
'}';
}
}
public class Client {
public static void main(String[] args) {
// 创建原型对象
Address address = new Address("北京");
Sheep originalSheep = new Sheep("多莉", 3, address);
// 克隆原型对象
Sheep clonedSheep = originalSheep.clone();
// 打印原始对象和克隆对象
System.out.println("原始羊: " + originalSheep);
System.out.println("克隆羊: " + clonedSheep);
// 修改原始对象的引用类型属性
address.setCity("上海");
// 再次打印原始对象和克隆对象
System.out.println("修改后的原始羊: " + originalSheep);
System.out.println("修改后的克隆羊: " + clonedSheep);
}
}
注意: 使用序列化和反序列化实现深拷贝,需要确保对象及其所有属性都实现了 Serializable
接口。
输出结果:
原始羊: Sheep{name='多莉', age=3, address=Address{city='北京'}}
克隆羊: Sheep{name='多莉', age=3, address=Address{city='北京'}}
修改后的原始羊: Sheep{name='多莉', age=3, address=Address{city='上海'}}
修改后的克隆羊: Sheep{name='多莉', age=3, address=Address{city='北京'}}
分析:
可以看到,修改原始羊的地址后,克隆羊的地址没有改变!这是因为深拷贝复制了地址的所有信息,原始羊和克隆羊拥有不同的地址,所以一个变了,另一个不会受到影响!
优点:
缺点:
Cloneable
接口才能被复制,就像需要贴上“允许复制”的标签,有点麻烦!希望这篇文章能让你彻底理解原型模式!