1. 原型模式
1.1 概述
原型模式是一种创建型设计模式,通过复制已有的实例来创建新对象,而不是通过实例化类来创建。这种模式适用于创建复杂对象或者频繁创建和销毁对象的场景。原型模式通过定义一个接口来声明复制方法,具体的实现类需要实现这个方法。
1.2 结构
原型模式包含如下角色:
- 原型接口(Prototype):定义一个接口,声明克隆方法。
- 具体原型类(ConcretePrototype):实现原型接口,提供具体的克隆功能。
- 客户端(Client):使用原型来创建对象,而无需关心对象的具体类。
接口类图如下:
1.3 实现
原型模式的克隆分为浅克隆和深克隆。
浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。
Java
中的 Object
类中提供了 clone()
方法来实现浅克隆。 Cloneable
接口是上面的类图中的原型接口,而实现了 Cloneable
接口的子实现类就是具体原型类。代码如下:
// 具体原型类
public class ConcretePrototype implements Cloneable {
private String field;
public ConcretePrototype(String field) {
System.out.println("具体原型对象创建完成!");
this.field = field;
}
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
@Override
public ConcretePrototype clone() throws CloneNotSupportedException {
System.out.println("具体原型复制成功!");
return (ConcretePrototype) super.clone();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
// 输出:具体的原型对象创建完成!
ConcretePrototype original = new ConcretePrototype("Hello");
// 输出:具体原型复制成功!
ConcretePrototype clone = original.clone();
System.out.println("===修改前===");
// 输出:原始数据:Hello
System.out.println("原始数据:" + original.getField());
// 输出:克隆数据:Hello
System.out.println("克隆数据:" + clone.getField());
System.out.println(original == clone);
// 修改克隆对象的字段
clone.setField("World");
System.out.println("===修改后===");
// 输出:原始数据:Hello
System.out.println("原始数据:" + original.getField());
// 输出:克隆数据:World
System.out.println("克隆数据:" + clone.getField());
// 判断获取到的两个实例是否是同一个对象, 输出:false
System.out.println(original == clone);
}
}
1.3.1 案例
用原型模式生成“三好学生”奖状
同一学校的“三好学生”奖状除了获奖学生不同,其他都相同,可以使用原型模式复制多个“三好学生”奖状出来,然后在修改奖状上的学生即可。
1.3.1.1 浅克隆
浅克隆是指在克隆对象时,它会创建一个新的对象,新对象的非基本类型(引用类型)属性将与原对象的相应属性指向相同的内存地址。也就是说,浅克隆只是简单地复制对象的基本类型属性的值,而对于对象中的引用类型属性,只是复制了引用,而不是复制引用所指向的对象本身。
// 学生类
public class Student {
// 学生的姓名
private String name;
// 学生的地址
private String address;
public Student(String name, String address) {
this.name = name;
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
// 奖状类
public class Citation implements Cloneable {
private Student student;
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public void show() {
System.out.println(student.getName() + "同学:在2024学年第一学期中表现优秀,被评为三好学生。特发此状!");
System.out.println("奖状将会发往:" + student.getAddress() + "市");
}
@Override
public Citation clone() throws CloneNotSupportedException {
return (Citation) super.clone();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Citation citation1 = new Citation();
Student student1 = new Student("张三", "西安");
citation1.setStudent(student1);
// 复制奖状
Citation citation2 = citation1.clone();
// 获取citation2奖状所属学生对象
Student student2 = citation2.getStudent();
student2.setName("李四");
student2.setAddress("上海");
// 判断student1对象和student2对象是否是同一个对象
System.out.println("student1和student2是同一个对象?" + (student1 == student2));
// 输出:
// 李四同学:在2024学年第一学期中表现优秀,被评为三好学生。特发此状!
// 奖状将会发往:上海市
citation1.show();
// 输出:
// 李四同学:在2024学年第一学期中表现优秀,被评为三好学生。特发此状!
// 奖状将会发往:上海市
citation2.show();
}
}
student1
和 student2
是同一个对象,就会产生将 student1
对象中 name
属性值改为“李四”,address
属性值改为“上海”,两个 citation
对象中显示的都是李四。这就是浅克隆的效果,对 具体原型类(Citation) 中的引用类型的属性进行引用的复制。这种情况需要使用深克隆,而进行深克隆需要使用对象流。
1.3.1.2 深克隆
深克隆(Deep Clone)是指在克隆对象时,不仅要复制对象本身的值,还要复制对象内部引用的所有对象,确保克隆出的对象与原对象完全独立。与浅克隆相比,深克隆能避免引用类型数据的共享。
1.3.1.2.1 深克隆的两种常见方法
- 实现
Cloneable
接口并进行手动深拷贝 - 通过序列化机制实现深拷贝
1.3.1.2.2 手动深拷贝
在这种方法中,所有可变的引用类型属性都需要调用其 clone()
方法来进行克隆。这种方法的优势是灵活性,但可能需要手动处理对象的各个层级,尤其是多级引用时实现起来会较为复杂。
// 学生类
public class Student implements Cloneable {
// 学生的姓名
private String name;
// 学生的地址
private String address;
public Student(String name, String address) {
this.name = name;
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public Student clone() throws CloneNotSupportedException {
return (Student) super.clone();
}
}
// 奖状类
public class Citation implements Cloneable {
private Student student;
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public void show() {
System.out.println(student.getName() + "同学:在2024学年第一学期中表现优秀,被评为三好学生。特发此状!");
System.out.println("奖状将会发往:" + student.getAddress() + "市");
}
@Override
public Citation clone() throws CloneNotSupportedException {
Citation clonedCitation = (Citation) super.clone();
// 手动克隆引用类型
clonedCitation.setStudent(clonedCitation.getStudent().clone());
return clonedCitation;
}
}
// 客户端代码
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Citation citation1 = new Citation();
Student student1 = new Student("张三", "西安");
citation1.setStudent(student1);
// 复制奖状
Citation citation2 = citation1.clone();
// 获取citation2奖状所属学生对象
Student student2 = citation2.getStudent();
student2.setName("李四");
student2.setAddress("上海");
// 判断student1对象和student2对象是否是同一个对象
System.out.println("student1和student2是同一个对象?" + (student1 == student2));
// 输出:
// 张三同学:在2024学年第一学期中表现优秀,被评为三好学生。特发此状!
// 奖状将会发往:西安市
citation1.show();
// 输出:
// 李四同学:在2024学年第一学期中表现优秀,被评为三好学生。特发此状!
// 奖状将会发往:上海市
citation2.show();
}
}
1.3.1.2.3 手动深拷贝优缺点
- 优点:
- 灵活:可以精确控制每个引用属性的拷贝方式。
- 缺点:
- 实现复杂:每个引用类型属性都需要手动克隆,特别是嵌套对象时,代码复杂度会增加。
1.3.1.2.4 序列化方式深拷贝
这种方法借助 Java 的序列化机制,将对象序列化为字节流,再将其反序列化为一个新的对象,从而实现深拷贝。该方法简单且通用,适合于深拷贝复杂对象。
// 学生类
public class Student implements Serializable {
// 学生的姓名
private String name;
// 学生的地址
private String address;
public Student(String name, String address) {
this.name = name;
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
// 奖状类
public class Citation implements Serializable {
private Student student;
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public void show() {
System.out.println(student.getName() + "同学:在2024学年第一学期中表现优秀,被评为三好学生。特发此状!");
System.out.println("奖状将会发往:" + student.getAddress() + "市");
}
public Citation deepClone() throws IOException, ClassNotFoundException {
// 写入字节流
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
// 读取字节流
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (Citation) ois.readObject();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Citation citation1 = new Citation();
Student student1 = new Student("张三", "西安");
citation1.setStudent(student1);
// 复制奖状
Citation citation2 = citation1.deepClone();
// 获取citation2奖状所属学生对象
Student student2 = citation2.getStudent();
student2.setName("李四");
student2.setAddress("上海");
// 判断student1对象和student2对象是否是同一个对象
System.out.println("student1和student2是同一个对象?" + (student1 == student2));
// 输出:
// 张三同学:在2024学年第一学期中表现优秀,被评为三好学生。特发此状!
// 奖状将会发往:西安市
citation1.show();
// 输出:
// 李四同学:在2024学年第一学期中表现优秀,被评为三好学生。特发此状!
// 奖状将会发往:上海市
citation2.show();
}
}
注意:
Citation
类和Student
类必须实现Serializable
接口,否则会抛NotSerializableException
异常。
1.3.1.2.5 序列化方式深拷贝优缺点
- 优点:
- 简单:不需要手动编写克隆逻辑,序列化和反序列化会自动处理整个对象图的拷贝。
- 通用性:适用于对象图中包含多层级引用关系的复杂对象。
- 缺点:
- 需要类实现
Serializable
接口。 - 性能较低:序列化和反序列化相对较慢,可能对性能有影响,特别是大对象时。
1.4 原型模式优缺点
- 优点
- 性能优化:通过克隆已经存在的对象,可以避免重复初始化和复杂构造过程,从而提高性能。
- 动态性:原型模式可以在运行时决定需要克隆的具体对象,支持灵活的对象创建。
- 简化对象创建:对于复杂对象,使用原型克隆相较于构造器更加简单直观,尤其是当对象的构造需要很多步骤时。
- 缺点
-
实现复杂性:需要实现
clone
方法,对于一些复杂对象,可能涉及深拷贝和浅拷贝的实现,使得代码复杂。 - 依赖问题:如果原型对象内部含有复杂的依赖关系或者不可变对象,克隆时可能会导致状态不一致的问题。
-
限制:在 Java 中,如果原型类没有实现
Cloneable
接口,调用clone()
方法会抛出异常。需要额外的处理。
1.5 总结
原型模式是一种有效的对象创建方式,尤其适用于对象构造复杂或者频繁创建和销毁的情况。通过克隆已有的实例,可以简化对象创建过程,提高性能,但在实现时需要关注克隆的复杂性和对象状态的一致性问题。
2. 建造者模式
2.1 概述
建造者模式(Builder Pattern)是一种创建型设计模式,用于将复杂对象的创建过程与其表示分离。它允许逐步构建对象,并根据需要动态选择其组成部分,最终通过一个建造者将对象“组装”起来。建造者模式的核心在于将一个复杂对象的构建与它的表示分离开,这样同样的构建过程可以创建不同的表示。
2.2 结构
- 产品(Product):表示要构建的复杂对象。
- 抽象建造者(Builder):定义构建对象的步骤,通常包括设置部件的抽象方法。
-
具体建造者(ConcreteBuilder):实现
Builder
接口,完成实际对象的创建步骤,并返回最终的复杂对象。 - 指挥者(Director):控制构建过程的逻辑,将建造的步骤按特定顺序执行。
-
客户端(Client):使用
Director
和Builder
来生成产品。
接口类图如下:
2.3 实现
// 汉堡类,表示要构建的产品
public class Burger {
// 面包
private String bread;
// 肉饼
private String patty;
// 沙拉
private String salad;
// 酱料
private String sauce;
public void setBread(String bread) {
this.bread = bread;
}
public void setPatty(String patty) {
this.patty = patty;
}
public void setSalad(String salad) {
this.salad = salad;
}
public void setSauce(String sauce) {
this.sauce = sauce;
}
@Override
public String toString() {
return "汉堡里面有:" + bread + "," + patty + "," + salad + "和" + sauce;
}
}
// 抽象的建造者,定义了构建汉堡的步骤
public interface BurgerBuilder {
void buildBread();
void buildPatty();
void buildSalad();
void buildSauce();
// 返回构建好的汉堡
Burger getBurger();
}
// 具体建造者,构建一款经典汉堡
public class ClassicBurgerBuilder implements BurgerBuilder {
private final Burger burger;
public ClassicBurgerBuilder() {
this.burger = new Burger();
}
@Override
public void buildBread() {
burger.setBread("白面包");
System.out.println("使用白面包...");
}
@Override
public void buildPatty() {
burger.setPatty("牛肉饼");
System.out.println("添加牛肉饼...");
}
@Override
public void buildSalad() {
burger.setSalad("生菜");
System.out.println("添加生菜...");
}
@Override
public void buildSauce() {
burger.setSauce("番茄酱");
System.out.println("添加番茄酱...");
}
@Override
public Burger getBurger() {
return this.burger;
}
}
// 具体建造者,构建一款素食汉堡
public class VeggieBurgerBuilder implements BurgerBuilder {
private final Burger burger;
public VeggieBurgerBuilder() {
this.burger = new Burger(); // 初始化汉堡
}
@Override
public void buildBread() {
burger.setBread("全麦面包");
System.out.println("使用全麦面包...");
}
@Override
public void buildPatty() {
burger.setPatty("豆腐饼");
System.out.println("添加豆腐饼...");
}
@Override
public void buildSalad() {
burger.setSalad("黄瓜");
System.out.println("添加黄瓜...");
}
@Override
public void buildSauce() {
burger.setSauce("芥末酱");
System.out.println("添加芥末酱...");
}
@Override
public Burger getBurger() {
return this.burger;
}
}
// 指挥者,负责控制构建的过程
public class BurgerDirector {
private final BurgerBuilder burgerBuilder;
public BurgerDirector(BurgerBuilder burgerBuilder) {
this.burgerBuilder = burgerBuilder;
}
// 控制建造过程
public Burger makeBurger() {
burgerBuilder.buildBread();
burgerBuilder.buildPatty();
burgerBuilder.buildSalad();
burgerBuilder.buildSauce();
// 返回构建好的汉堡
return burgerBuilder.getBurger();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
// 创建具体的建造者
BurgerBuilder builder1 = new ClassicBurgerBuilder();
BurgerBuilder builder2 = new VeggieBurgerBuilder();
// 创建指挥者并传入建造者
BurgerDirector director1 = new BurgerDirector(builder1);
BurgerDirector director2 = new BurgerDirector(builder2);
// ===开始构建经典汉堡===
// 使用白面包...
// 添加牛肉饼...
// 添加生菜...
// 添加番茄酱...
System.out.println("===开始构建经典汉堡===");
Burger burger1 = director1.makeBurger();
// ===开始构建素食汉堡===
// 使用全麦面包...
// 添加豆腐饼...
// 添加黄瓜...
// 添加芥末酱...
System.out.println("===开始构建素食汉堡===");
Burger burger2 = director2.makeBurger();
System.out.println("======");
// 输出:构建好的经典汉堡: 汉堡里面有:白面包,牛肉饼,生菜和番茄酱
System.out.println("构建好的经典汉堡: " + burger1);
// 输出:构建好的素食汉堡: 汉堡里面有:全麦面包,豆腐饼,黄瓜和芥末酱
System.out.println("构建好的素食汉堡: " + burger2);
}
}
注意:
上面示例是Builder
模式的常规用法,指挥者类Director
在建造者模式中具有很重要的作用,它用于指导具体构建者如何构建产品,控制调用先后次序,并向调用者返回完整的产品类,但是有些情况下需要简化系统结构,可以把指挥者类和抽象建造者进行结合。
// 抽象的建造者和指挥者,定义了构建汉堡的步骤并且负责控制构建的过程
public abstract class BurgerBuilder {
protected Burger burger = new Burger();
abstract void buildBread();
abstract void buildPatty();
abstract void buildSalad();
abstract void buildSauce();
abstract Burger getBurger();
// 控制建造过程
public Burger makeBurger() {
this.buildBread();
this.buildPatty();
this.buildSalad();
this.buildSauce();
// 返回构建好的汉堡
return this.getBurger();
}
}
// 具体建造者,构建一款经典汉堡
public class ClassicBurgerBuilder extends BurgerBuilder {
private final Burger burger;
public ClassicBurgerBuilder() {
this.burger = new Burger();
}
@Override
public void buildBread() {
burger.setBread("白面包");
System.out.println("使用白面包...");
}
@Override
public void buildPatty() {
burger.setPatty("牛肉饼");
System.out.println("添加牛肉饼...");
}
@Override
public void buildSalad() {
burger.setSalad("生菜");
System.out.println("添加生菜...");
}
@Override
public void buildSauce() {
burger.setSauce("番茄酱");
System.out.println("添加番茄酱...");
}
@Override
public Burger getBurger() {
return this.burger;
}
}
// 具体建造者,构建一款素食汉堡
public class VeggieBurgerBuilder extends BurgerBuilder {
private final Burger burger;
public VeggieBurgerBuilder() {
this.burger = new Burger(); // 初始化汉堡
}
@Override
public void buildBread() {
burger.setBread("全麦面包");
System.out.println("使用全麦面包...");
}
@Override
public void buildPatty() {
burger.setPatty("豆腐饼");
System.out.println("添加豆腐饼...");
}
@Override
public void buildSalad() {
burger.setSalad("黄瓜");
System.out.println("添加黄瓜...");
}
@Override
public void buildSauce() {
burger.setSauce("芥末酱");
System.out.println("添加芥末酱...");
}
@Override
public Burger getBurger() {
return this.burger;
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
// 创建具体的建造者
BurgerBuilder builder1 = new ClassicBurgerBuilder();
BurgerBuilder builder2 = new VeggieBurgerBuilder();
// ===开始构建经典汉堡===
// 使用白面包...
// 添加牛肉饼...
// 添加生菜...
// 添加番茄酱...
System.out.println("===开始构建经典汉堡===");
Burger burger1 = builder1.makeBurger();
// ===开始构建素食汉堡===
// 使用全麦面包...
// 添加豆腐饼...
// 添加黄瓜...
// 添加芥末酱...
System.out.println("===开始构建素食汉堡===");
Burger burger2 = builder2.makeBurger();
System.out.println("======");
// 输出:构建好的经典汉堡: 汉堡里面有:白面包,牛肉饼,生菜和番茄酱
System.out.println("构建好的经典汉堡: " + burger1);
// 输出:构建好的素食汉堡: 汉堡里面有:全麦面包,豆腐饼,黄瓜和芥末酱
System.out.println("构建好的素食汉堡: " + burger2);
}
}
这样做确实简化了系统结构,但同时也加重了抽象建造者类的职责,也不是太符合单一职责原则,如果建造过程过于复杂,建议还是封装到 Director
中。
2.4 建造者模式优缺点
- 优点
- 更好的控制对象创建过程:通过分步骤创建对象,每一步可以自由选择不同的细节,最终得到精确定制的产品。
- 代码更简洁、更灵活:客户端无需关心复杂对象的创建过程,只需通过指挥者调用建造者来构建对象。
- 解耦创建和表示:在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
-
扩展性好:通过实现不同的
ConcreteBuilder
,可以灵活创建多种表示的产品,而无需修改现有的指挥者和产品类。因此也就不会对原有功能引入风险。符合开闭原则。
- 缺点
-
产品内部构建过程较复杂时可能增加复杂性:虽然建造者模式解耦了对象的构建,但如果产品本身过于复杂,可能需要很多
Builder
子类来完成具体的构建任务,反而增加系统的复杂度。 -
需要有稳定的构建过程:如果产品的构建过程频繁变化,可能需要频繁修改
Builder
接口及其实现类。 - 需要有共同点:建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
2.5 使用场景
- 需要分步骤创建复杂对象:对象由多个部分组成,并且对象的创建步骤依赖于某些条件或者顺序。
- 不同表示的对象使用同样的构建过程:同样的创建步骤可以构建出不同的对象表示。
- 需要将对象的创建过程与表示分离:在需要解耦对象的构建与它的具体表示时,使用建造者模式可以减少耦合。
2.6 模式扩展
建造者模式除了上面的用途外,在开发中还有一个常用的使用方式,就是当一个类构造器需要传入很多参数时,如果创建这个类的实例,代码可读性会非常差,而且很容易引入错误,此时就可以利用建造者模式进行重构。
重构前代码如下:
// 电脑类
public class Computer {
// CPU
private String CPU;
// 屏幕
private String screen;
// 内存条
private String memory;
// 主板
private String mainboard;
public Computer(String CPU, String screen, String memory, String mainboard) {
this.CPU = CPU;
this.screen = screen;
this.memory = memory;
this.mainboard = mainboard;
}
public String getCPU() {
return CPU;
}
public void setCPU(String CPU) {
this.CPU = CPU;
}
public String getScreen() {
return screen;
}
public void setScreen(String screen) {
this.screen = screen;
}
public String getMemory() {
return memory;
}
public void setMemory(String memory) {
this.memory = memory;
}
public String getMainboard() {
return mainboard;
}
public void setMainboard(String mainboard) {
this.mainboard = mainboard;
}
@Override
public String toString() {
return "Computer{" +
"CPU='" + CPU + '\'' +
", screen='" + screen + '\'' +
", memory='" + memory + '\'' +
", mainboard='" + mainboard + '\'' +
'}';
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
// 构建电脑对象
Computer computer = new Computer("intel", "三星屏幕", "金士顿", "华硕");
// 输出:Computer{CPU='intel', screen='三星屏幕', memory='金士顿', mainboard='华硕'}
System.out.println(computer);
}
}
上面在客户端代码中构建 Computer
对象,传递了四个参数,如果参数更多呢?代码的可读性及使用的成本就是比较高。
重构后代码:
// 电脑类
public class Computer {
// CPU
private final String CPU;
// 屏幕
private final String screen;
// 内存条
private final String memory;
// 主板
private final String mainboard;
private Computer(Builder builder) {
this.CPU = builder.CPU;
this.screen = builder.screen;
this.memory = builder.memory;
this.mainboard = builder.mainboard;
}
@Override
public String toString() {
return "Computer{" +
"CPU='" + CPU + '\'' +
", screen='" + screen + '\'' +
", memory='" + memory + '\'' +
", mainboard='" + mainboard + '\'' +
'}';
}
public static final class Builder {
private String CPU;
private String screen;
private String memory;
private String mainboard;
public Builder() {
}
public Builder CPU(String CPU) {
this.CPU = CPU;
return this;
}
public Builder screen(String screen) {
this.screen = screen;
return this;
}
public Builder memory(String memory) {
this.memory = memory;
return this;
}
public Builder mainboard(String mainboard) {
this.mainboard = mainboard;
return this;
}
public Computer build(){
return new Computer(this);
}
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
// 构建电脑对象
Computer computer1 = new Computer.Builder()
.CPU("intel")
.mainboard("华硕")
.memory("金士顿")
.screen("三星")
.build();
Computer computer2 = new Computer.Builder()
.CPU("AMD")
.mainboard("微星")
.screen("LG")
.memory("芝奇")
.build();
// 输出:Computer{CPU='intel', screen='三星屏幕', memory='金士顿', mainboard='华硕'}
System.out.println(computer1);
// 输出:Computer{CPU='AMD', screen='LG', memory='芝奇', mainboard='微星'}
System.out.println(computer2);
}
}
重构后的代码在使用起来更方便,某种程度上也可以提高开发效率。从软件设计上,对程序员的要求比较高。
2.7 总结
建造者模式通过将复杂对象的构建过程与它的最终表示解耦,为对象创建提供了灵活性和可扩展性。它可以灵活地构建多种不同的对象,适用于对象需要分步骤创建并且具有多个不同表示的场景。但当对象的构建过程非常复杂或频繁变化时,建造者模式的实现可能会变得冗长和复杂。