在软件设计中,创建型设计模式主要用于对象的创建过程,以减少直接使用“new”关键字实例化对象带来的复杂性。本文将详细介绍两种常见的创建型设计模式:原型模式和建造者模式。我们将从定义、实现、优缺点以及应用场景等方面进行探讨,并结合实际代码示例帮助读者更好地理解和应用这些模式。
一、原型设计模式
(一)定义
原型模式(Prototype Pattern)是一种对象创建型模式,它通过拷贝一个现有的对象来创建一个新的对象,而不是通过“new”关键字实例化。这种方式可以显著提高对象的创建效率,尤其是在创建新对象成本较高时。
(二)实现
原型模式的核心是实现Cloneable
接口或Serializable
接口,从而实现对象的浅拷贝或深拷贝。以下是一个简单的实现示例:
import java.io.*;
import java.util.ArrayList;
import java.util.List;
// 声明克隆方法的接口
public interface Prototype extends Cloneable {
Prototype clone() throws CloneNotSupportedException;
}
// 具体原型类
public class Person implements Prototype, Serializable {
private String name;
private int age;
private List<String> list = new ArrayList<>();
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 浅拷贝
@Override
public Person clone() throws CloneNotSupportedException {
return (Person) super.clone();
}
// 深拷贝
public Person deepClone() throws IOException, ClassNotFoundException {
// 输出序列化
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
// 输入反序列化
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return (Person) ois.readObject();
}
// 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 List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", list=" + list +
'}';
}
}
(三)优缺点
-
优点:
-
创建新对象时性能更高,尤其是当对象创建成本较高时。
-
可以通过克隆现有对象来快速生成新对象,简化对象的创建过程。
-
可以用于实现撤销操作,通过深克隆保存对象状态。
-
-
缺点:
-
需要为每个类实现克隆方法,对已有类进行改造时需要修改源代码,违背开闭原则。
-
实现深克隆时代码较为复杂,尤其是当对象存在多重嵌套引用时。
-
(四)应用场景
-
当创建新对象成本较高时,可以通过克隆现有对象来快速生成新对象。
-
当需要保存对象的状态时,可以使用深克隆来保存对象的备份。
二、建造者模式
(一)定义
建造者模式(Builder Pattern)是一种创建型设计模式,它将一个复杂对象的构建过程与其表示分离,使得相同的构建过程可以创建不同的表示。它允许用户通过指定复杂对象的类型和内容来构建对象,而无需了解内部的具体构建细节。
(二)实现
建造者模式的核心是定义一个抽象建造者接口和多个具体建造者类。以下是一个简单的实现示例:
// 抽象建造者
public interface Builder {
void buildCpu();
void buildMainboard();
void buildDisk();
void buildPower();
void buildMemory();
Computer createComputer();
}
// 具体建造者
public class HighComputerBuilder implements Builder {
private Computer computer = new Computer();
@Override
public void buildCpu() {
computer.setCpu("高配 CPU");
}
@Override
public void buildMainboard() {
computer.setMainboard("高配 主板");
}
@Override
public void buildDisk() {
computer.setDisk("高配 磁盘");
}
@Override
public void buildPower() {
computer.setPower("高配 电源");
}
@Override
public void buildMemory() {
computer.setMemory("高配 内存");
}
@Override
public Computer createComputer() {
return computer;
}
}
// 指挥者
public class Director {
public Computer create(Builder builder) {
builder.buildMemory();
builder.buildCpu();
builder.buildMainboard();
builder.buildDisk();
builder.buildPower();
return builder.createComputer();
}
}
// 产品类
public class Computer {
private String cpu;
private String mainboard;
private String disk;
private String power;
private String memory;
// Getter 和 Setter 方法
public String getCpu() {
return cpu;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
public String getMainboard() {
return mainboard;
}
public void setMainboard(String mainboard) {
this.mainboard = mainboard;
}
public String getDisk() {
return disk;
}
public void setDisk(String disk) {
this.disk = disk;
}
public String getPower() {
return power;
}
public void setPower(String power) {
this.power = power;
}
public String getMemory() {
return memory;
}
public void setMemory(String memory) {
this.memory = memory;
}
@Override
public String toString() {
return "Computer{" +
"cpu='" + cpu + '\'' +
", mainboard='" + mainboard + '\'' +
", disk='" + disk + '\'' +
", power='" + power + '\'' +
", memory='" + memory + '\'' +
'}';
}
}
(三)优缺点
-
优点:
-
将产品的构建过程与产品的表示分离,客户端无需了解内部的具体构建细节。
-
每个具体建造者相对独立,便于扩展新的建造者。
-
符合开闭原则,增加新的具体建造者无需修改原有代码。
-
可以结合链式编程,使代码更加美观。
-
-
缺点:
-
产品一般具有较多的共同点,如果产品差异较大则不建议使用。
-
代码量可能会增加,因为需要定义多个类(抽象建造者、具体建造者、指挥者等)。
-
(四)应用场景
-
当需要构建一个复杂的对象时,且对象的构建过程较为复杂。
-
当需要隐藏对象的构建细节,只暴露最终的产品时。
-
当需要构建多个具有相同构建过程但不同表示的对象时。
三、原型模式与建造者模式的比较
(一)相同点
-
都是创建型设计模式,用于对象的创建过程。
-
都可以提高对象的创建效率,减少直接使用“new”关键字带来的复杂性。
(二)不同点
-
功能:
-
原型模式通过拷贝现有对象来创建新对象,适合快速复制对象。
-
建造者模式通过逐步构建对象的各个部分来创建对象,适合构建复杂的对象。
-
-
实现:
-
原型模式主要通过实现
Cloneable
或Serializable
接口来实现浅拷贝或深拷贝。 -
建造者模式通过定义抽象建造者接口和具体建造者类来实现对象的逐步构建。
-
-
适用场景:
-
原型模式适用于创建新对象成本较高,或需要保存对象状态的场景。
-
建造者模式适用于构建复杂的对象,且需要隐藏对象的构建细节的场景。
-
原型模式和建造者模式都是创建型设计模式,它们在对象创建过程中提供了不同的解决方案。原型模式通过拷贝现有对象来快速生成新对象,适合快速复制和保存对象状态的场景;而建造者模式通过逐步构建对象的各个部分来创建复杂的对象,适合构建复杂对象且需要隐藏构建细节的场景。在实际开发中,可以根据具体需求选择合适的模式来实现功能。