Skip to content

2026-04-02 星期四

【职场/管理】能量与能力的认知差异(任老师)


在职业发展中,能量往往比能力更具决定性。

  • 能量: 指一个人的内在动力、抗压能力、积极心态以及对他人的感染力。
  • 能力: 指执行具体任务的技术、知识和熟练度。

💡 感悟: 能力决定了你能走多快,而能量决定了你能走多远。

【设计模式】【面试考点】工厂模式与建造者模式的核心维度区别


对比维度工厂模式建造者模式
核心意图创建不同类型但具备相关性的对象,实现多态性构建同一类型内部结构复杂的对象
产品复杂度通常创建单一、完整的独立对象通常创建由多个部件/属性组成的复合对象
构建过程一步到位,单次调用方法直接返回完整对象分步进行,多步配置后由 build() 方法最终组装成品
核心关注点关注对象整体类型的选择关注对象内部细节的装配过程
行业经典示例LoggerFactory.getLogger()Java StringBuilder、Lombok @Builder

【最佳实践】工厂模式的 Java 后端高频使用场景


工厂模式的核心适用场景为:需要根据不同条件动态创建不同具体实现类的场景,Java 后端开发中高频落地场景如下:

  1. 多类型数据库/中间件客户端创建:根据配置文件的类型,动态创建 MySQL、PostgreSQL 等不同数据库的连接对象,上层业务代码无需感知底层实现差异
  2. 多环境日志记录器适配:根据运行环境,自动切换 ConsoleLogger(开发环境)、FileLogger/KafkaLogger(生产环境),无需修改业务代码
  3. 多格式文件解析器创建:根据上传文件的后缀名,自动创建 PdfParserExcelParser 等对应格式的解析器实现类

【最佳实践】建造者模式的 Java 后端高频使用场景


建造者模式的核心适用场景为:需要创建参数繁多、构造逻辑复杂的对象,或需要创建不可变(Immutable)对象的场景,Java 后端开发中高频落地场景如下:

  1. 复杂配置类/组件对象构建:例如线程池 ThreadPoolExecutor 这类包含7个以上核心参数的对象,通过链式调用分步配置参数,大幅提升代码可读性
  2. 动态构建类场景:例如 SQL 构建器、HTTP Request 构建器,通过分步调用方法拼接参数,最终生成完整的 SQL 语句或请求对象
  3. 不可变对象创建:对于创建后不允许修改(无 setter 方法)、但初始化需要大量参数的对象,通过 Builder 模式完成合法参数校验与对象初始化

【后端框架】【Spring IoC 容器】基于 XML 管理 Bean 对象


  • 获取 Bean 方式:
    • XML 配置属性:id、class、id 和 class (保证唯一性)
    • FactoryBean(整合第三方框架的常用机制):实现 FactoryBean<?> 接口来减少配置 XML 操作
  • 对象赋值:
    • 初始化 Bean 对象(DI 注入):setter(property)、constructor(constructor-arg)
    • 常规属性赋值:”ref”、内部 Bean、级联属性 “clazz.clazzname”
    • 特殊属性赋值:数组类(&lt;array>&lt;value>)、List 类(&lt;list>&lt;ref>)、Map 类(&lt;entry>&lt;key>&lt;value>&lt;ref>)
    • 引用集合类型赋值:使用 &lt;util> 进行引用赋值
    • 通过 p 命名空间赋值:&lt;bean p:property=“xxx”>&lt;/bean>
    • 外部配置文件赋值:利用 &lt;context> 名称空间,将 .property 配置文件注入对象属性 “${a.b}”
  • 特殊符号处理:&lt;null/>、“&lt;”、&lt;![CDATA[a < b]]>
  • Bean 的作用域(scope):singleton(默认单例、初始化时创建)、prototype(多例、获取 Bean 时创建)
  • Bean 的生命周期:(能画个图说明最好)
    • bean对象创建(调用无参构造器)

    • 给bean对象设置属性

    • bean的后置处理器(初始化之前)(init-method)

    • bean对象初始化(需在配置bean时指定初始化方法)

    • bean的后置处理器(初始化之后)(destroy-method)

    • bean对象就绪可以使用

    • bean对象销毁(需在配置bean时指定销毁方法)

    • IoC容器关闭

【算法经验】快速排序


原理:分治策略、哨兵划分、递归排序

复杂度:$O(nlogn) - O(n)$,最坏时间复杂度 $O(n^2)$

核心思想: 通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

关键步骤:

  1. 基准数选择: 选择一个数作为基准(Pivot)。
  2. 哨兵划分: 将大于基准的移到右边,小于基准的移到左边。
  3. 递归排序: 对左右子区间重复上述过程。

优势:

  • 概率论: 出现最差情况的概率极低。
  • 缓存友好: 执行划分操作时,子数组连续加载到缓存,访问效率高;跳跃式访问元素的,缺乏该特性
  • 常数系数小:快速排序的比较、赋值、交换等操作的总数量最少
C++
int partition(vector&lt;int> &nums, int left, int right) {
    int i = left, j = right; // 双指针分治
    while (i &lt; j) { // 结束条件:指针相遇,遍历结束,i 左边全小于基数,j 右边全大于基数
        while (i&lt;j && nums[j]>=nums[left]) --j; // 从右往左遍历,比基数大的不管,直到下一个比基数小的停止
        while (i&lt;j && nums[i]&lt;=nums[left]) ++i; // 从左往右遍历,比基数小的不管,直到下一个比基数大的停止
        swap(nums[i], nums[j]); // 交换 i,j 下标的元素,把当前比基数大的,放到 j 路径后面,比基数小的,放到 i 路径后面
    } // ⚠⚠⚠ 因为先动的是 j 指针,一定是 j 指针碰到 i 指针,即 j==i ,这个时候 i/j 下标的数是一定是比基数小的数,交换 i 跟 left 下标的数后,当前整个区间基准数就被移到了中间,左边一定是全比基数小的。这是因为默认 left 下标是基数的原因,如果默认 right 下标为基数的话,那么就应该先动 i 指针,让 i 指针与 j 指针相遇,最后交换 i 跟 right 之后,右边的数一定全是大于基数的数
    swap(nums[i], nums[left]);
    return i;
}

void quickSort(vector&lt;int> &nums, int left, int right) {
	if (left >= right) return; // 子数组长度为 1 时终止递归
    // 当前这个区间的基准数是 left
	int pivot = partition(nums, left, right); // 获取临界点(这个点左边的数都小于 left,右边的数都大于 left)
    // 在 partition 中最后将 left 跟 pivot 交换了位置,所以上面一行的 pivot 实际上是快排之后的 left 的下标
    // 下面中的 left 仍然是当前区间的 left 边界,**作用域**搞清楚
    // [left, a, b, c, pivot, A, B, C, right]
    quickSort(nums, left, pivot-1); // 小于 left 的所有数的区间进行快排
    quickSort(nums, pivot+1, right); // 大于 left 的所有数的区间进行快排
}

TODO:

  • Spring 跟 Springboot 的具体差异

  • 只有用 IoC 容器管理的实体才能被 Springboot 使用吗?组件跟实体的区别

  • 注解管理 Bean ,各个注解的作用、运用场景

记录学习,分享技术