首页 > 其他分享 >【设计模式(五)】创建型模式--建造者模式

【设计模式(五)】创建型模式--建造者模式

时间:2024-07-05 14:52:48浏览次数:9  
标签:String -- 创建 Builder 模式 void private 设计模式 public

创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是“将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。

概述:建造者模式注重的是部件构建的过程,意在通过一步一步地精确构造创建出一个复杂的对象。

建造者(Builder)模式包含如下角色

  • 抽象建造者类(Builder):这个接口规定要实现复杂对象的哪些部分的创建,并不涉及具体的部件对象的创建。

  • 具体建造者类(ConcreteBuilder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。在构造过程完成后,提供产品的实例。

  • 产品类(Product):要创建的复杂对象。

  • 指挥者类(Director):调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。

创建共享单车

生产自行车是一个复杂的过程,它包含了车架,车座等组件的生产。而车架又有碳纤维,铝合金等材质的,车座有橡胶,真皮等材质。对于自行车的生产就可以使用建造者模式。

这里Bike是产品,包含车架,车座等组件;Builder是抽象建造者,MobikeBuilder和OfoBuilder是具体的建造者;Director是指挥者。类图如下:

产品

//自行车类
public class Bike {
    private String frame;
    private String seat;

    public String getFrame() {
        return frame;
    }

    public void setFrame(String frame) {
        this.frame = frame;
    }

    public String getSeat() {
        return seat;
    }

    public void setSeat(String seat) {
        this.seat = seat;
    }
}

抽象构造者

// 抽象 builder 类
public abstract class Builder {

    protected Bike mBike = new Bike();

    public abstract void buildFrame();
    public abstract void buildSeat();
    public abstract Bike createBike();
}

具体构造者

//摩拜单车Builder类
public class MobikeBuilder extends Builder {

    @Override
    public void buildFrame() {
        mBike.setFrame("铝合金车架");
    }

    @Override
    public void buildSeat() {
        mBike.setSeat("真皮车座");
    }

    @Override
    public Bike createBike() {
        return mBike;
    }
}

//ofo单车Builder类
public class OfoBuilder extends Builder {

    @Override
    public void buildFrame() {
        mBike.setFrame("碳纤维车架");
    }

    @Override
    public void buildSeat() {
        mBike.setSeat("橡胶车座");
    }

    @Override
    public Bike createBike() {
        return mBike;
    }
}

指挥者

//指挥者类
public class Director {
    private Builder mBuilder;

    public Director(Builder builder) {
        mBuilder = builder;
    }

    public Bike construct() {
        //负责组装自行车
        mBuilder.buildFrame();
        mBuilder.buildSeat();
        return mBuilder.createBike();
    }
}

//客户端测试类
public class Client {
    public static void main(String[] args) {
        showBike(new OfoBuilder());
        showBike(new MobikeBuilder());
    }
    private static void showBike(Builder builder) {
        Director director = new Director(builder);
        Bike bike = director.construct();
        System.out.println(bike.getFrame());
        System.out.println(bike.getSeat());
    }
}

注意:

上面示例是 Builder模式的常规用法,指挥者类 Director 在建造者模式中具有很重要的作用,它用于指导具体构建者如何构建产品,控制调用先后次序,并向调用者返回完整的产品类,但是有些情况下需要简化系统结构,可以把指挥者类和抽象建造者进行结合

// 抽象 builder 类
public abstract class Builder {

    protected Bike mBike = new Bike();

    public abstract void buildFrame();
    public abstract void buildSeat();
    public abstract Bike createBike();
    
    public Bike construct() {
        this.buildFrame();
        this.BuildSeat();
        return this.createBike();
    }
}

说明:

这样做确实简化了系统结构,但同时也加重了抽象建造者类的职责,也不是太符合单一职责原则,如果construct() 过于复杂,建议还是封装到 Director 中。

优点:

  • 建造者模式的封装性很好。使用建造者模式可以有效的封装变化,在使用建造者模式的场景中,一般产品类和建造者类是比较稳定的,因此,将主要的业务逻辑封装在指挥者类中对整体而言可以取得比较好的稳定性。
  • 在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象
  • 可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
  • 建造者模式很容易进行扩展。如果有新的需求,通过实现一个新的建造者类就可以完成,基本上不用修改之前已经测试通过的代码,因此也就不会对原有功能引入风险。符合开闭原则。

缺点:

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

模式扩展
建造者模式除了上面的用途外,在开发中还有一个常用的使用方式,就是当一个类构造器需要传入很多参数时,如果创建这个类的实例,代码可读性会非常差,而且很容易引入错误,此时就可以利用建造者模式进行重构。

public class Phone {

    private String cpu;
    private String screen;
    private String memory;
    private String mainboard;

    private Phone(Builder builder) {
        cpu = builder.cpu;
        screen = builder.screen;
        memory = builder.memory;
        mainboard = builder.mainboard;
    }

    public static final class Builder {
        private String cpu;
        private String screen;
        private String memory;
        private String mainboard;

        public Builder() {}

        public Builder cpu(String val) {
            cpu = val;
            return this;
        }
        public Builder screen(String val) {
            screen = val;
            return this;
        }
        public Builder memory(String val) {
            memory = val;
            return this;
        }
        public Builder mainboard(String val) {
            mainboard = val;
            return this;
        }
        public Phone build() {
            return new Phone(this);}
    }
    @Override
    public String toString() {
        return "Phone{" +
                "cpu='" + cpu + '\'' +
                ", screen='" + screen + '\'' +
                ", memory='" + memory + '\'' +
                ", mainboard='" + mainboard + '\'' +
                '}';
    }
}

public class Client {
    public static void main(String[] args) {
        Phone phone = new Phone.Builder()
                .cpu("intel")
                .mainboard("华硕")
                .memory("金士顿")
                .screen("三星")
                .build();
        System.out.println(phone);
    }
}

标签:String,--,创建,Builder,模式,void,private,设计模式,public
From: https://www.cnblogs.com/hudad/p/18284200

相关文章

  • 低代码框架选型注意事项
    低代码框架这些年在企业软件行业可谓是烂大街的一个概念,网上一搜各种低代码框架琳琅满目,搜索引擎翻十页不带重样的。笔者在一个甲方公司的信息部搬砖,今年遇到过几次和软件供应商交流完产品和解决方案后,供应商强调他们是的底座是个低代码平台,后期运维开发很快,着实让人想不到。......
  • Maven依赖排除和冲突解决
    maven中有很多包会重复引入依赖,首先jar包冲突后会有就近原则和先声明者优先(前面的优先)作为一个专业的开发,我们掌握的工具必须齐全,尽量少重复造轮子,但要知道轮子原理:mavenhelp其次是依赖排除,这两张图显示.Conflicts显示重复依赖AllDependenciesasList集合形式显示......
  • 面试必会之JAVA基础篇
    1.Final有什么用?被final修饰的类不可以被继承被final修饰的方法不可以被重写被final修饰的变量不可以被改变被final修饰不可变的是变量的引用,而不是引用指向的内容,引用指向的内容是可以改变的finalArrayList<Integer>finalList=newArrayList<>();//初始化后,finalL......
  • PyTorch基本操作
    PyTorch基本操作torch.allclose是一个PyTorch函数,用于检查两个张量是否在某个容忍度范围内近似相等torch.allclose(input,other,rtol=1e-05,atol=1e-08,equal_nan=False)input(Tensor)–第一个输入张量other(Tensor)–第二个输入张量rtol(float)–相对容忍度a......
  • 空洞文件
    实际上这些数据并没有被存储在磁盘上。当创建一个空洞文件时,文件系统会记录这些“空洞”,但并不会在物理介质上实际分配和保存未使用的空间,从而节省了实际的存储空间。举例来说,如果你创建一个大小为1GB的空洞文件,其中写入了大量的零字节据,实际上只有少量的数据(例如文件指针处......
  • Box,一个字典操作python库
     Box介绍Box是一个让字典操作变得异常简单与直观,支持通过属性访问字典内容的库。 特点概述属性访问Box允许用户像访问对象属性一样访问字典的值,提升了代码的可读性和易用性。无缝嵌套自动将嵌套的字典转换为Box对象,使得处理复杂字典结构变得轻而易举。灵活性......
  • Python速通(条件语句)
    (牛牛的选择)牛牛在牛客网经过了两次笔试分别获得了Tencent和Alibaba的面试资格,不巧的是这两次面试的时间冲突了。两家公司牛牛都想去,他决定通过笔试的成绩判断去参加哪家公司的面试。现在输入两行浮点数,分别表示牛牛在Tencent和Alibaba的笔试成绩,请比较两个成绩,输出笔试成绩较高的......
  • 断点续传:使用java对大文件进行分块与合并
    通常我们下载上传的视频文件比较大。虽然https协议没有规定上传文件大小的限制,但是网络的质量,电脑硬件的参差不齐可能会导致大文件快要上传完成的时候突然断网了要重新上传,非常影响用户体验。以此我们引入了断点续传的功能。什么是断点续传呢?就是我们在上传下载文件的时候,将一个......
  • 安装Redis出现的问题
    当我使用brew下载redis时系统:macOS14$brewinstallredis报错信息:Error:git:unknownorunsupportedmacOSversion::dunnoError:'git'mustbeinstalledandinyourPATH!Warning:YouareusingmacOS14.Wedonotprovidesupportforthispre-releaseve......
  • VMware vSphere Tanzu部署_16_TKC集群节点VM密码获取
    SupervisorControlPlaneVM密码获取通过SSH方式登录vcentervcenter开启SSH服务通过SSH工具登录vcenter执行获取密码脚本在vcentershell模式下执行/usr/lib/vmware-wcp/decryptK8Pwd.py命令WARNING!TheremoteSSHserverrejectedX11forwardingrequest.Connect......