zoukankan      html  css  js  c++  java
  • 创建型设计模式(三)建造者模式

     文章更新时间:2020/06/29

    一、一句话背景

      比如目前我需要实现一个功能,根据我输入的参数来获取具体的游戏角色对象,而游戏角色的组成是很繁杂的,这种情况我们就可以考虑使用建造者模式来开发这一个功能。

    二、使用场景

      使用场景:获取一个复杂对象,同时对象的内部组合逻辑多变的场景。

      如:组合搭配出产品的需求

      优点:我们只关注需要生成的对象是不是我们需要的,而不关注对象生成和内部的具体组成过程。

    三、模型分析

    产品角色:需要获取的具体产品,是包含多个组成部件的复杂对象,由具体建造者来创建其各个部件。

    抽象建造者:包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法 getResult()。

    具体建造者:实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。

    指挥者:它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。

    四、代码分析

    对象创建类

    /**
     * 玩家对象【产品角色】
     */
    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;//护甲
    
        public 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);
        }
    
        /**
         * 内部类【同时担任 抽象建造者/具体建造者】
         */
        public static final 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);
            }
        }
    }

    调用类

    /**
     * 建造者模式测试类【模拟初始化创建一个游戏角色】
     */
    public class BuilderTest {
        public static void main(String[] args) {
         //传参过程中实际上就类似于调用“具体的创建者”来生成“产品”,这样写,链式传参更加灵活 Player gunMan
    = new Player.Builder() .name("张皓") .hairstyle("光头") .sex("汉子") .shape("强壮得一批~") .height("180cm") .weapon("长剑") .armor("重甲") .build(); } }

    代码分析:

      首先需要声明一下,这种写法不是传统意义上的建造者模式,传统的建造者模式一般会有上面所说的四个对象,这里做了一个整合,把四个角色整合到了一起。

      Q:为什么要写一个内层的Builder来对外层的产品对象进行属性设置呢?这不是多此一举么?

      A:当前写法主要是考虑以下几个方面:

    • 1、构造函数可能存在多个的情况(想象一下如果有很多构造方法,首先每个构造函数的可读性就不好,很容易传错,你还要去看构造方法内的每个参数是什么含义,再考虑选用哪个构造方法,想想在调用的时候疯不疯...)
    • 2、链式调用结构更加清晰,扩展也方便
    • 3、方便创建属性固定后续不再变更的对象实例(这里需要解释一下,因为建造者模式实质上就是为了创建对象;如果采用传统的getter,setter方法,也就是javaBean的方式也是可以实现的,但是这样在调用的时候,属性一般是分开设置的,对象的状态也容易改变,所以如果是在创建时就需要固定设置好内部属性的情况时,就写成final的形式,先把需要设置的参数设置好,防止后续状态变更)
  • 相关阅读:
    可遇不可求的Question之过滤单词字符的正则表达式\w的疑义
    可遇不可求的Question之DBNull.Value.ToString()
    可遇不可求的Question之MYSQL的10060和10061错误篇
    可遇不可求的Question之正在中止线程异常
    可遇不可求的Question之类型初始值设定项引发异常篇
    可遇不可求的Question之调用的目标发生了异常篇
    可遇不可求的Question之要复制的 LOB 数据的长度超出了配置的最大值篇
    熱海へ
    CC的留言
    研发才是硬道理钢铁侠的评论(摘自豆瓣)
  • 原文地址:https://www.cnblogs.com/riches/p/11208655.html
Copyright © 2011-2022 走看看