设计模式创建者模式 之原型模式&构建者模式

设计模式构建者模式(其实我觉得应该叫模块或板块 都一样理解就好)已经趋于尾声

这期学习的是原型模式和构建者模式 为什么放在一起呢 感觉原型模式理解起来比较简单 构建者模式呢 实际开发中用框架的库比较多 自己写的情况较少 除非特别复杂的应用场景  所以说一起介绍首先原型模式

概念

通过克隆现有对象来创建新对象,而不是通过实例化新对象。在原型模式中,我们通过复制一个现有对象的状态来创建新的对象,而无需关心对象的具体类别。

比较通俗吧!但有人就会好奇 为什么我要拷贝而不是自己new呢?原因和应用场景如下

原因和应用场景

  1. 性能提升: 对于某些对象的创建和初始化过程比较复杂耗时的情况,通过原型模式可以避免重新执行这些耗时的初始化步骤。通过克隆现有对象,可以省去对象的初始化过程,提升性能。

  2. 动态创建: 原型模式允许在运行时动态创建对象,而不需要在代码中硬编码特定类的实例化。这使得系统更加灵活,能够根据需要选择创建不同类型的对象。

  3. 复杂对象的创建: 当对象的创建过程比较复杂,涉及多个步骤或依赖关系时,使用原型模式可以避免手动编写繁琐的构造函数,并确保对象的正确初始化。

  4. 避免构造函数的执行: 在一些情况下,直接使用 new 实例化对象会调用对象的构造函数,而这可能不是我们所期望的,特别是在对象的创建过程中可能会执行一些与原型无关的逻辑。通过克隆,可以避免构造函数的执行,只复制对象的状态。

  5. 保持对象的独立性: 当需要创建对象的副本而不影响原始对象时,使用原型模式是一种更好的选择。克隆会生成一个独立的对象,对其状态的修改不会影响原始对象。

总的来说,原型模式在一些特定的场景下能够提供更灵活、高效且清晰的对象创建机制,特别适用于创建过程复杂、性能敏感或需要动态创建的对象。

角色

  1. 抽象原型角色: 定义了克隆方法的接口或抽象类。具体的原型类要实现这个接口或继承这个抽象类。

  2. 具体原型角色: 实现了抽象原型接口,负责实现对象的克隆方法。具体原型对象被复制以生成新的对象。

深克隆浅克隆的区别

浅拷贝: 拷贝对象时,只复制基本数据类型的成员变量,对于引用类型的成员变量,仅复制引用,而不复制引用指向的对象。因此,新对象和原对象共享引用类型成员变量所引用的对象。

深拷贝: 拷贝对象时,不仅复制对象本身,还复制对象中引用类型成员变量所引用的对象。因此,新对象和原对象的引用类型成员变量引用的是两个不同的对象。

代码

浅克隆

在下面demo中Cloneable 就是抽象原型角色Prototype 就是具体原型角色

class MutableData {
    /**
     * 即使在浅拷贝中,如果拷贝的是不可变对象(如 String),对拷贝对象的修改也不会影响原对象。如果拷贝的是可变对象,那么对拷贝对象的修改可能会影响原对象,因为它们共享相同的引用。
     * 所以说定义了这样的一个类 让引用的地址是这个对象的地址而不是string
     */
    private String value;

    public MutableData(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}

class Prototype implements Cloneable {
    private MutableData data;

    public Prototype(String value) {
        this.data = new MutableData(value);
    }

    public void setData(String value) {
        this.data.setValue(value);
    }

    @Override
    public Prototype clone() {
        try {
            return (Prototype) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }

    public String getData() {
        return data.getValue();
    }
}

public class Client {
    public static void main(String[] args) {
        // 创建具体原型对象
        Prototype prototype = new Prototype("aaa");

        // 使用克隆方法创建新对象
        Prototype clone = prototype.clone();

        // 修改克隆对象的数据
        clone.setData("bbb");

        // 输出原型对象和克隆对象的数据
        System.out.println(prototype.getData());  // 输出:bbb
        System.out.println(clone.getData());      // 输出:bbb
    }
}
深克隆

只做一个简单的实现 该类必须实现 Serializable接口 如果该类的成员变量有其他类(组合或聚合)

那么其他类也需要 实现Serializable接口

package com.nvl.nvl.Test;

import lombok.SneakyThrows;

import java.io.*;

class Student implements Serializable {
    private String name;


    public Student(String name) {
        this.name = name;

    }

    public void setName(String name) {
        this.name = name;
    }

    // 实现深拷贝的方法
    @SneakyThrows
    public Student clone() {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);

        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);

        return (Student) ois.readObject();
    }

    public String getName() {
        return name;
    }

}


public class DeepCopyDemo {
    public static void main(String[] args) {

            Student student = new Student("ck");
            Student clone = student.clone();
            System.out.println(student.getName());
            clone.setName("ck2");
            System.out.println(clone.getName());

    }
}

构建者模式

概念

使得构建过程和最终对象分离。通过将一个大的复杂对象的构建过程分解为多个步骤,每个步骤由一个具体的构建者来负责,客户端可以通过指定不同的构建者来创建不同的产品。

构建者模式的主要目标是将一个复杂对象的构建与其表示分离,以便同样的构建过程可以创建不同的表示。这有助于提高灵活性和可维护性,同时简化了客户端的构建代码。

角色

  1. 产品: 表示被构建的复杂对象,它通常包含多个部分。
  2. 抽象构建者: 声明构建产品各个部分的抽象接口。
  3. 具体构建者: 实现抽象构建者接口,负责构建产品的具体部分,并提供一个获取产品的方法。
  4. 指导者: 构建产品的具体步骤,调用具体构建者来构建产品

流程

  1. 定义产品的抽象类或接口,明确定义产品的各个部分。
  2. 创建一个抽象构建者接口,其中包含创建产品各个部分的抽象方法。
  3. 创建具体构建者类,实现抽象构建者接口,负责构建产品的各个部分。
  4. 创建导演类,负责控制构建的流程,按照一定的步骤调用具体构建者的方法构建产品。
  5. 客户端通过创建具体构建者和导演来构建具体的产品。

代码

举例来说,假设我们要构建一个电脑对象,它包含 CPU、内存和硬盘等部分。构建者模式可以将构建过程分解成设置 CPU、内存和硬盘的步骤,每个步骤由具体构建者来实现。指导者则协调这些步骤的顺序,客户端可以选择不同的具体构建者来构建出不同配置的电脑对象。

如果有不同的构建方式 那么就新建一个类实现抽象构建者接口

// 产品类
class Computer {
    private String cpu;
    private String memory;
    private String hardDisk;

    public Computer(String cpu, String memory, String hardDisk) {
        this.cpu = cpu;
        this.memory = memory;
        this.hardDisk = hardDisk;
    }

    @Override
    public String toString() {
        return "Computer [CPU=" + cpu + ", Memory=" + memory + ", HardDisk=" + hardDisk + "]";
    }
}

// 抽象构建者
interface ComputerBuilder {
    void buildCPU(String cpu);
    void buildMemory(String memory);
    void buildHardDisk(String hardDisk);
    Computer getResult();
}

// 具体构建者
class ConcreteComputerBuilder implements ComputerBuilder {
    private Computer computer;

    public ConcreteComputerBuilder() {
        this.computer = new Computer("", "", "");
    }

    @Override
    public void buildCPU(String cpu) {
        computer.cpu = cpu;
    }

    @Override
    public void buildMemory(String memory) {
        computer.memory = memory;
    }

    @Override
    public void buildHardDisk(String hardDisk) {
        computer.hardDisk = hardDisk;
    }

    @Override
    public Computer getResult() {
        return computer;
    }
}

// 指导者
class Director {
    public void construct(ComputerBuilder builder) {
        builder.buildCPU("Intel i7");
        builder.buildMemory("16GB");
        builder.buildHardDisk("512GB SSD");
    }
}

// 客户端
public class BuilderPatternDemo {
    public static void main(String[] args) {
        // 创建具体构建者
        ComputerBuilder builder = new ConcreteComputerBuilder();

        // 创建指导者并构建电脑
        Director director = new Director();
        director.construct(builder);

        // 获取构建结果
        Computer computer = builder.getResult();

        // 输出构建的电脑对象
        System.out.println(computer);
    }
}

优点

  • 建造者模式的封装性很好。使用建造者模式可以有效的封装变化,在使用建造者模式的场景中,一般产品类和建造者类是比较稳定的,因此,将主要的业务逻辑封装在指挥者类中对整体而言可以取得比较好的稳定性

  • 在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。

  • 可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。

  • 建造者模式很容易进行扩展。如果有新的需求,通过实现一个新的建造者类就可以完成,基本上不用修改之前已经测试通过的代码因此也就不会对原有功能引入风险。符合开闭原则。

缺点

造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。

就好比上面代码只适合去构建电脑类的对象 要是想构建其他的他就用不了了

实际开发写法

在这个示例中,Computer 类的构造函数是私有的,只能通过 Builder 类来构建 Computer 对象。Builder 类中包含了一系列设置属性的方法,并且这些方法返回的都是 Builder 类自身,使得可以通过链式调用一系列的设置方法。最后,通过 build() 方法来创建 Computer 对象。

在很多框架中很多都是这么实现的 比如lombok builder注解 

这种实现方式有以下优点:

  • 避免了构造函数的多个参数,提高了代码的可读性。
  • 可以在 Builder 类中设置默认值,使得在构建对象时,只需要设置感兴趣的属性。

class Computer {
    private String cpu;
    private String memory;
    private String hardDisk;

    private Computer(Builder builder) {
        cpu = builder.cpu;
        memory = builder.memory;
        hardDisk = builder.hardDisk;
    }

    public static final class Builder {
        private String cpu;
        private String memory;
        private String hardDisk;

        public Builder cpu(String cpu) {
            this.cpu = cpu;
            return this;
        }

        public Builder memory(String memory) {
            this.memory = memory;
            return this;
        }

        public Builder hardDisk(String hardDisk) {
            this.hardDisk = hardDisk;
            return this;
        }

        public Computer build() {
            return new Computer(this);
        }
    }

    public static void main(String[] args) {
        Computer computer = new Computer.Builder()
                .cpu("cpu")
                .memory("memory")
                .hardDisk("hardDisk")
                .build();
    }
}

总结

以上就是原型模式和构建者模式 至此 创建者模式完结

 之前更新过的:

单例模式:设计模式 创建者模式之 单例模式-CSDN博客​​​​​​

工厂模式:设计模式 创建者模式之 工厂模式-CSDN博客                       

  • 49
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值