设计模式学习(七)建造者模式
文章更新时间:2021/08/23
一、一句话背景
比如目前我需要实现一个功能,根据我输入的参数来获取具体的游戏角色对象,而游戏角色的组成是很繁杂的,这种情况我们就可以考虑使用建造者模式来开发这一个功能。
二、使用场景
使用场景:获取一个复杂对象,同时对象的内部组合逻辑多变的场景。
如:组合搭配出产品的需求
优点:我们只关注需要生成的对象是不是我们需要的,而不关注对象生成和内部的具体组成过程。
三、模型分析
产品角色:需要获取的具体产品,是包含多个组成部件的复杂对象,由具体建造者来创建其各个部件。
抽象建造者:包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法build()。
具体建造者:实现Builder接口,完成复杂产品的各个部件的具体创建方法。
指挥者:它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。
四、代码演示
对象创建类
/** * 玩家【产品】 * * @author 有梦想的肥宅 * @date 2021/8/23 */ public class Player { private final String name;//名字 private final String hairstyle;//发型 private final String sex;//性别 private final String shape;//体型 private final String height;//身高 private final String weapon;//武器 private final String armor;//护甲 //无参构造方法可以设为私有,意味着复杂对象不直接new出来 private Player() { throw new RuntimeException("使用建造者模式时,复杂产品不直接实例化具体对象"); } /** * 有参构造方法【指挥者】 */ private Player(Builder builder) { this.name = builder.name == null ? "未设置" : builder.name; this.hairstyle = builder.hairstyle == null ? "未设置" : builder.hairstyle; this.sex = builder.sex == null ? "未设置" : builder.sex; this.shape = builder.shape == null ? "未设置" : builder.shape; this.height = builder.height == null ? "未设置" : builder.height; this.weapon = builder.weapon == null ? "未设置" : builder.weapon; this.armor = builder.armor == null ? "未设置" : builder.armor; System.out.println("新建了一个玩家角色:"); System.out.println(" 名字:" + this.name); System.out.println(" 发型:" + this.hairstyle); System.out.println(" 性别:" + this.sex); System.out.println(" 体型:" + this.shape); System.out.println(" 身高:" + this.height); System.out.println(" 武器:" + this.weapon); System.out.println(" 护甲:" + this.armor); } /** * 静态内部类【同时担任 抽象建造者/具体建造者】 * PS:设置为静态的是为了可以外部直接调用 */ public static class Builder { private String name;//名字 private String hairstyle;//发型 private String sex;//性别 private String shape;//体型 private String height;//身高 private String weapon;//武器 private String armor;//护甲 public Builder name(String val) { name = val; return this;//返回当前builder对象(为了在使用时,可以使用链式调用的方式) } public Builder hairstyle(String val) { hairstyle = val; return this;//返回当前builder对象(为了在使用时,可以使用链式调用的方式) } public Builder sex(String val) { sex = val; return this;//返回当前builder对象(为了在使用时,可以使用链式调用的方式) } public Builder shape(String val) { shape = val; return this;//返回当前builder对象(为了在使用时,可以使用链式调用的方式) } public Builder height(String val) { height = val; return this;//返回当前builder对象(为了在使用时,可以使用链式调用的方式) } public Builder weapon(String val) { weapon = val; return this;//返回当前builder对象(为了在使用时,可以使用链式调用的方式) } public Builder armor(String val) { armor = val; return this;//返回当前builder对象(为了在使用时,可以使用链式调用的方式) } //返回最终完成属性组装的复杂产品对象 public Player build() { return new Player(this); } } }
调用类
/** * 建造者模式测试类【模拟初始化创建一个游戏角色】 * * @author 有梦想的肥宅 * @date 2021/8/23 */ public class BuilderTest { public static void main(String[] args) { //1、建造一个战士角色 Player warrior = new Player.Builder() .name("有梦想的肥宅") .hairstyle("光头") .sex("男性") .shape("相当强壮") .height("180cm") .weapon("长剑") .armor("重甲") .build(); //2、建造一个射手角色 Player shooter = new Player.Builder() .name("阿靓") .hairstyle("长发") .sex("女性") .shape("身材曼妙") .height("159.999999cm") .weapon("橡木弓") .armor("布甲") .build(); } }
五、代码分析
首先需要声明一下,这种写法不是传统意义上的建造者模式,传统的建造者模式一般会有上面所说的四个对象,这里做了一个整合,把四个角色整合到了一起。
Q:为什么要写一个内层的Builder来对外层的产品对象进行属性设置呢?这不是多此一举么?
当前写法主要是考虑以下几个方面:
- 1、构造函数可能存在多个的情况(想象一下如果有很多构造方法,首先每个构造函数的可读性就不好,很容易传错,你还要去看构造方法内的每个参数是什么含义,再考虑选用哪个构造方法,想想在调用的时候疯不疯...)
- 2、链式调用结构更加清晰,扩展也方便
- 3、方便创建属性固定后续不再变更的对象实例(这里需要解释一下,因为建造者模式实质上就是为了创建对象,如果采用传统的getter,setter方法,也就是javaBean的方式也是可以实现的,但是这样在调用的时候,属性一般是分开设置的,对象的状态也容易改变,所以如果是在创建时就需要固定设置好内部属性的情况时,就写成final的形式,先把需要设置的参数设置好,防止后续状态变更)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律