原型模式(Prototype)
一、问题
在某些情况下,需要创建对象的副本,但复制一个对象的成本可能很高,或者希望避免与对象的具体类耦合。例如,当创建对象的过程较为复杂,或者对象包含大量共享的状态时,使用常规的创建方法可能会导致性能下降。
二、解决方案
原型模式的解决方案是通过复制现有对象来创建新对象,而不是从头开始构建。这允许我们以更高效的方式创建新对象,同时避免了与对象类的直接耦合。核心概念是在原型对象的基础上进行克隆,使得新对象具有与原型相同的初始状态。 在原型模式中,通常会有以下几个角色:
- 抽象原型(Prototype):声明克隆方法,作为所有具体原型的基类或接口。
- 具体原型(Concrete Prototype):实现克隆方法,从自身创建一个副本。
- 客户端(Client):使用原型对象的客户端代码,在需要新对象时通过克隆现有对象来创建新实例。
三、效果
原型模式的应用可以带来以下效果:
- 减少对象创建的成本:避免了复杂对象的重复初始化过程,提高了创建对象的效率。
- 避免与具体类耦合:客户端可以通过克隆方法创建新对象,而无需知道具体类的细节,降低了耦合度。
- 灵活性增加:可以在运行时动态地添加或删除原型,适应不同的对象创建需求。
- 支持动态配置:可以通过克隆来定制对象的不同配置,而无需修改其代码。
然而,也需要注意一些限制,如:
- 深克隆问题:原型模式默认进行浅克隆,即复制对象本身和其引用。如果对象内部包含其他对象的引用,可能需要实现深克隆来复制整个对象结构。
- 克隆方法的实现:某些对象可能不容易进行克隆,特别是涉及到文件、网络连接等资源的情况。
总之,原型模式是一种在需要创建对象副本时非常有用的设计模式,它提供了一种灵活且高效的方法来处理对象的复制需求。
四、代码
1.Person.java
/**
* Person
*
* @author 裴浩宇
* @version 1.0
* @date 2023/11/3 17:13
* @description 人
*/
public class Person implements Cloneable{
// 姓名
private String name;
// 年龄
private Integer age;
// 住址
private Address address;
@Override
public Person clone() {
Person clone = null;
try {
clone = (Person) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address=" + address +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
java
2.Address.java
/**
* Address
*
* @author 裴浩宇
* @version 1.0
* @date 2023/11/3 17:14
* @description 地址
*/
public class Address {
// 省
private String province;
// 市
private String city;
// 区
private String area;
@Override
public String toString() {
return "Address{" +
"province='" + province + '\'' +
", city='" + city + '\'' +
", area='" + area + '\'' +
'}';
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getArea() {
return area;
}
public void setArea(String area) {
this.area = area;
}
}
java
3.Main.java
/**
* Main
*
* @author 裴浩宇
* @version 1.0
* @date 2023/11/3 17:18
* @description 客户端
*/
public class Main {
public static void main(String[] args) {
Person p = new Person();
p.setName("Pei你看雪");
p.setAge(18);
Address address = new Address();
address.setProvince("山东省");
address.setCity("济南市");
address.setArea("历区城");
p.setAddress(address);
Person q = p;
Person z = p.clone();
p.setAge(19);
p.getAddress().setArea("高新区");
System.out.println("q" + q);
System.out.println("z" + z.toString());
}
}
java
4.打印结果
从输出结果可以看到,使用
=
赋值方式创建对象时,两个对象共享相同的引用类型字段;而使用原型模式创建对象时,新对象是独立于原对象的,不会共享引用类型字段。 因此,在需要创建新对象并避免共享引用类型字段的情况下,建议使用原型模式。 当然,对于对象中的引用类型字段,只会复制引用,新对象与原对象将共享同一个引用类型对象。