分别暴露、统一暴露以及默认暴露三者的区别

一、分别暴露 export

1.注意:export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系。

// 报错

export 1;

// 报错

var m = 1;

export m;

2.所谓变量,其实只有在声明时的一瞬间有,声明过后,不管是单独使用,还是作为实参传递,它都是作为一个表达式,而不是变量。

二、统一暴露 export {}

1. 统一暴露的语法 export {} 中 {} 是一个对象吗?

export {} 是作为一个整体的语法存在,在{}中放入的是模块需要对外暴露内部变量,在形式上其实这里{}更像是一个数组,其数组元素就是模块内部变量。

三、默认暴露 export default

1. 默认暴露和上面两种暴露最大的区别是,一个模块中默认暴露只能使用一次,而export 和 export {} 可以使用多次。

2. 默认暴露主要场景就是,针对一个模块只暴露一个接口的场景。

3.export 只暴露一个接口的场景:导出时需要满足一一对应要求,导入时需要使用import {}命令接收

// b.js

export function b(){

    console.log('b')

}

// a.js

import {b} from './b.js'

4. export {} 只暴露一个接口的场景:导出时必须要搞一个变量名给export {} 命令,否则export {} 无法获取变量,且必须使用 import {} 命令接收

// b.js

var b = function(){

    console.log('b')

}

export {b}

// a.js

import {b} from './b.js'

5. export default 由于默认暴露只能暴露一个接口,所以这个接口不需要名字就可以限定,同时模块只会暴露一个接口给import,所以import也不需要名字限定,直接导出该接口即可,接口名可以任意定.

// b.js

export default function(){

    console.log('b')

}

// a.js

import haha from './b.js'

四、注意

export命令可以出现在模块的任何位置,只要处于模块顶层就可以。如果处于块级作用域内,就会报错,下一节的import命令也是如此。 需要注意的是,import和export命令是在编译期间工作的,而无论是无论是函数块,if块,代码块,它们之中的代码都是在运行期间才能生效的,所以必须将import和export命令放置于模块顶层。

<think> 我们需要设计一个类,只暴露`builder()`静态方法来创建构建器对象,而不直接暴露`Builder`类的构造方法。这通常用于实现构建器模式(Builder Pattern),确保使用者只能通过预定义的API来创建对象。 ### 实现步骤: 1. **将Builder类设为私有或包私有**:这样外部类就不能直接实例化Builder。 2. **通过外部类的静态方法返回Builder实例**:在外部类中提供一个静态方法`builder()`,它返回一个新的Builder实例。 ### 示例代码: ```java public class MyClass { private final String name; private final int age; // 私有构造方法,只能由Builder创建 private MyClass(Builder builder) { this.name = builder.name; this.age = builder.age; } // 暴露的静态方法,用于创建Builder public static Builder builder() { return new Builder(); } // Builder类:设为静态内部类,并且构造方法私有(或包私有) public static class Builder { private String name; private int age; // 将Builder的构造方法设为私有,这样外部只能通过MyClass.builder()获取实例 private Builder() {} public Builder name(String name) { this.name = name; return this; } public Builder age(int age) { this.age = age; return this; } public MyClass build() { return new MyClass(this); } } } ``` ### 关键点: - **Builder构造方法私有**:这样外部无法直接通过`new Builder()`来创建,只能通过`MyClass.builder()`来获取Builder实例。 - **MyClass的构造方法私有**:这样外部无法直接实例化MyClass,必须通过Builder来构建。 - **builder()方法**:是唯一获取Builder实例的入口。 ### 使用方式: ```java MyClass obj = MyClass.builder() .name("Alice") .age(25) .build(); ``` ### 优势: - **控制Builder的创建**:确保Builder的实例化只能通过我们提供的方法,可以在此方法中添加额外的逻辑(例如,初始化默认值)。 - **封装性**:隐藏了Builder的实现细节,防止外部不正确的使用。 ### 注意事项: - 如果Builder类需要被其他包使用,那么Builder类必须是public的,但它的构造方法可以设置为private,这样其他包中的类仍然无法直接实例化Builder,只能通过`MyClass.builder()`方法来获取实例。 §§相关问题§§ 1. 在构建器模式中,如何确保Builder的链式调用在子类继承中保持类型安全? 2. 如果构建器需要支持多个可选参数,如何避免构造函数参数列表过长的问题? 3. 如何为构建器设置默认参数值,并在多次调用同一设置方法时覆盖默认值? 4. 在构建器模式中,如何处理参数的校验逻辑? 5. 如何实现一个线程安全的构建器? </think> ### 如何只暴露 `builder()` 方法而不暴露 `Builder` 构造函数 在构建器模式中,核心目标是**让用户只能通过 `builder()` 方法获取构建器实例**,同时完全隐藏 `Builder` 类的构造方法。以下是四种实现方案: --- #### 方案一:静态内部类 + 私有构造(标准做法) ```java public class User { private final String name; // 其他字段... // ▶ 1. 私有主构造方法 private User(Builder builder) { this.name = builder.name; } // ▶ 2. 暴露的静态入口 ✅ public static Builder builder() { return new Builder(); // 唯一合法创建点 } // ▶ 3. 静态内部构建器类 public static final class Builder { private String name; // ★ 关键:私有构造方法(完全隐藏) private Builder() {} public Builder name(String name) { this.name = name; return this; } // ▶ 4. 最终构建方法 public User build() { return new User(this); } } } ``` **封堵漏洞**: - 外部无法实例化 `User`(主构造私有) - 外部无法直接实例化 `Builder`(构造私有) - 唯一入口:`User.builder()` --- #### 方案二:接口隔离法(防止误用) ```java // ▶ 构建器接口(暴露链式方法) public interface UserBuilder { UserBuilder name(String name); User build(); } public class User { // 主构造私有... public static UserBuilder builder() { // ▶ 返回实现类但向上转型为接口 return new BuilderImpl(); } // ★ 实现类不对外暴露 private static class BuilderImpl implements UserBuilder { private String name; // ▶ 包级私有构造(进一步限制) BuilderImpl() {} @Override public UserBuilder name(String name) { this.name = name; return this; } @Override public User build() { ... } } } ``` **优势**: - 用户只能看到接口方法(无法访问实现类构造) - 防止反射攻击:实现类对用户不可见 --- #### 方案三:工厂封装(企业级安全) ```java public final class UserFactory { // ▶ 禁用工厂类实例化 private UserFactory() { throw new AssertionError(); } public static Builder builder() { return new Builder(); } // ★ Builder作为工厂内部类 public static final class Builder { private Builder() {} // 构造私有 public User build() { ... } } } ``` **调用方式**: ```java // 唯一合法调用路径 ✅ User user = UserFactory.builder().name("Alice").build(); ``` --- #### 方案四:模块化屏障(Java 9+) ```module-info.java module user.module { exports com.example.user; // 只暴露User类 // 不导出Builder类(自动隐藏) } ``` ```java // ▶ 在独立未导出包中 package com.example.user.internal; class BuilderImpl { // 默认包级私有构造 BuilderImpl() {...} } // ▶ 在导出包中 package com.example.user; public class User { public static Builder builder() { return new internal.BuilderImpl(); } } ``` **效果**: - 用户代码无法访问 `internal` 包中的 `BuilderImpl` - 完全遵循 JPMS 模块访问控制 --- ### 关键防御措施总结 | 攻击方式 | 防御方案 | 效果 | |------------------|-----------------------------------|--------------------| | 直接实例化 Builder | 构造方法设为 `private` | ✅ 编译失败 | | 反射调用构造 | 接口隔离/模块隔离 | ✅ `IllegalAccess` | | 子类继承 Builder | 使用 `final` 修饰 Builder 类 | ✅ 阻断继承 | | 跨包实例化 | 包私有构造 + 模块隔离 | ✅ 访问错误 |
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值