第4课_原型模式实现
热度🔥:149 免费课程
授课语音
原型模式及其在 Java 中的实现
原型模式(Prototype Pattern)是一种创建型设计模式,旨在通过复制已有的实例来创建新的对象,而不是通过实例化一个新对象。该模式通过提供一个原型实例,并用该实例来创建新的对象,从而节省了创建对象的成本,尤其是在需要大量相似对象的场景下。
1. 原型模式的定义
原型模式的核心思想是:通过复制一个已有的对象来创建新的对象。它提供了一个原型接口,允许对象克隆自己,从而避免了重新创建对象的过程。
优点:
- 减少对象创建的开销,特别是在需要创建大量相似对象时。
- 可以在运行时动态配置对象属性。
- 原型模式可以实现深拷贝与浅拷贝的灵活选择。
缺点:
- 对象的拷贝可能会较为复杂,特别是在需要深拷贝的情况下。
- 需要显式地定义克隆方法,增加了代码的复杂度。
2. 原型模式的结构
原型模式通常包括以下几个角色:
- Prototype(原型接口):定义了克隆自身的接口。
- ConcretePrototype(具体原型类):实现了
clone()
方法,通过该方法实现自身的复制。 - Client(客户端):通过
Prototype
接口获取一个克隆对象,而不需要关心对象是如何被克隆的。
3. 原型模式的应用场景
原型模式适用于以下几种场景:
- 对象创建成本较高:通过复制已有的对象来节省新建对象的成本。
- 复杂的对象需要创建多个副本:通过克隆原型对象来快速创建相似对象。
- 当需要基于原型实例来创建对象,并且对象的创建过程可能会变得复杂时。
4. 在 Java 中实现原型模式
Java 中的 Object
类提供了 clone()
方法,可以用来实现对象的复制。我们可以通过覆盖 clone()
方法来实现原型模式。
4.1 浅拷贝与深拷贝
- 浅拷贝:创建一个新对象,新对象的成员变量与原对象的成员变量引用相同的内存地址。如果成员变量是引用类型,则修改新对象的引用类型成员变量会影响原对象。
- 深拷贝:创建一个新对象,并且新对象的成员变量是原对象成员变量的副本,即所有的引用类型成员变量会被重新复制一份,修改新对象的引用类型成员变量不会影响原对象。
5. 代码实现:浅拷贝与深拷贝
我们通过一个简单的例子来演示原型模式的实现,分为浅拷贝和深拷贝两种方式。
5.1 浅拷贝实现
// 原型接口,定义克隆方法
interface Prototype extends Cloneable {
Prototype clone(); // 复制自身
}
// 具体原型类
class ConcretePrototype implements Prototype {
private String name;
private int age;
// 构造方法
public ConcretePrototype(String name, int age) {
this.name = name;
this.age = age;
}
// 重写clone方法,实现浅拷贝
@Override
public Prototype clone() {
try {
return (Prototype) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
@Override
public String toString() {
return "ConcretePrototype{name='" + name + "', age=" + age + "}";
}
// Getter & Setter
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 class PrototypePatternDemo {
public static void main(String[] args) {
ConcretePrototype prototype1 = new ConcretePrototype("Alice", 25);
// 通过原型创建一个新对象
ConcretePrototype prototype2 = (ConcretePrototype) prototype1.clone();
// 输出原型对象与克隆对象
System.out.println("原型对象: " + prototype1);
System.out.println("克隆对象: " + prototype2);
}
}
5.2 深拷贝实现
为了演示深拷贝,我们需要确保所有成员变量都能被完全复制。
// 原型接口,定义克隆方法
interface Prototype extends Cloneable {
Prototype clone(); // 复制自身
}
// 具体原型类
class ConcretePrototype implements Prototype {
private String name;
private int age;
private Address address; // 引用类型成员变量
// 构造方法
public ConcretePrototype(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
// 重写clone方法,实现深拷贝
@Override
public Prototype clone() {
try {
ConcretePrototype clone = (ConcretePrototype) super.clone();
// 深拷贝引用类型成员变量
clone.address = new Address(address.getCity(), address.getStreet());
return clone;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
@Override
public String toString() {
return "ConcretePrototype{name='" + name + "', age=" + age + ", address=" + address + "}";
}
// Getter & Setter
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;
}
}
// 地址类,用于深拷贝示例
class Address {
private String city;
private String street;
public Address(String city, String street) {
this.city = city;
this.street = street;
}
@Override
public String toString() {
return "Address{city='" + city + "', street='" + street + "'}";
}
// Getter & Setter
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
}
// 客户端代码,演示原型模式的深拷贝
public class PrototypePatternDemo {
public static void main(String[] args) {
Address address = new Address("New York", "5th Avenue");
ConcretePrototype prototype1 = new ConcretePrototype("Alice", 25, address);
// 通过原型创建一个新对象
ConcretePrototype prototype2 = (ConcretePrototype) prototype1.clone();
// 修改克隆对象的地址
prototype2.getAddress().setCity("Los Angeles");
// 输出原型对象与克隆对象
System.out.println("原型对象: " + prototype1);
System.out.println("克隆对象: " + prototype2);
}
}
6. 代码注释
- 原型接口:定义了
clone()
方法,任何类实现该接口后,都可以克隆自身。 - ConcretePrototype:实现了
Prototype
接口,提供了浅拷贝和深拷贝的实现。在浅拷贝中,clone()
方法直接调用super.clone()
,而在深拷贝中,克隆对象后,还手动克隆了引用类型的成员变量。 - Address 类:示例中的引用类型,演示如何通过深拷贝解决引用类型的克隆问题。
- 客户端代码:演示了如何使用原型模式来克隆对象,以及如何修改克隆对象的状态。
7. 复杂度分析
- 时间复杂度:
clone()
方法的时间复杂度通常是O(n)
,其中n
是对象的成员变量数量。在深拷贝中,复杂度会更高,因为需要递归复制引用类型的成员变量。 - 空间复杂度:克隆操作需要占用额外的内存空间,空间复杂度是
O(n)
,其中n
是对象的成员变量数量。
8. 总结
原型模式通过提供一个原型对象并通过克隆该对象来创建新的实例,避免了重新创建对象的过程,尤其适用于对象创建成本较高或需要大量相似对象的场景。在 Java 中,我们可以通过 Cloneable
接口和 clone()
方法实现原型模式。