01、面向对象 vs 面向过程 vs 函数式

1、面向过程编程(Procedure Oriented Programming,POP)


  • 面向过程(Procedure Oriented):是一种编程范式或编程风格。
    • 以步骤为核心,把问题分解成一个个步骤,每个步骤用函数实现,按顺序调用这些函数即可。
      • 数据与方法是相互分离的。方法可以操作数据。
      • 数据:变量、属性。
    • 重点关注"如何一步步实现"。

  • 面向过程编程语言最大的特点:
    • 不支持类或对象两个语法概念,不支持面向对象编程的特性(如:封装、继承、多态),
    • 仅支持面向过程编程。

  • 面向过程的编程语言:
    • 如:C 语言。

  • 示例
    • 面向对象的语言,也能写出面向过程的代码。
package org.rainlotus.materials.javabase.a04_oop;

/**
 * @author zhangxw
 */
public class ProcessOriented {
    // 定义冰箱状态
    static boolean isDoorOpen = false;
    static String content = "";

    
    static void openFridge() {
        isDoorOpen = true;
        System.out.println("打开冰箱门");
    }

    static void putElephant(String elephant) {
        if (isDoorOpen) {
            content = elephant;
            System.out.println("放入" + elephant);
        }
    }

    static void closeFridge() {
        isDoorOpen = false;
        System.out.println("关闭冰箱门");
    }

    /**
     * 按步骤调用的静态函数
     * @param args
     */
    public static void main(String[] args) {
        openFridge();
        putElephant("大象");
        closeFridge();
    }
}

2、面向对象 (Object Oriented Programming,OOP)


  • 面向对象(Object Oriented):是一种编程范式或编程风格。
    • 以对象为核心,把问题分解成一个个步骤,对每个步骤进行相应的抽象,形成对象。
      • 数据与函数(方法)被封装在类中。通过方法来操作数据。
      • 不同对象之间,通过继承、组合实现解决问题。
    • 重点关注"谁来做什么",强调抽象、封装、继承、多态,将它们作为代码设计和实现的基石 。
  • 面向对象的编程语言:
    • 如:Java、C++ 语言。

  • 如:Elephant、Fridge 类用面向对象的思想去实现的。
    • 但是,main 方法内部的逻辑还是用面向过程的思想去实现的。
package org.rainlotus.materials.javabase.a04_oop;

/**
 * 大象类
 */
class Elephant {
    private String name;
    public Elephant(String name) { this.name = name; }
    public String getName() { return name; }
}

/**
 * 冰箱类
 */
class Fridge {
    private boolean isDoorOpen;
    private Elephant content;

    public void openDoor() {
        isDoorOpen = true;
        System.out.println("打开冰箱门");
    }

    public void store(Elephant elephant) {
        if (isDoorOpen) {
            content = elephant;
            System.out.println("放入" + elephant.getName());
        }
    }

    public void closeDoor() {
        isDoorOpen = false;
        System.out.println("关闭冰箱门");
    }
}

/**
 * @author zhangxw
 */
public class ObjectOriented {
    public static void main(String[] args) {
        Fridge fridge = new Fridge();
        Elephant elephant = new Elephant("大象");

        fridge.openDoor();
        fridge.store(elephant);
        fridge.closeDoor();
    }
}

3、函数式编程(Functional Programming,FP)


  • 函数式编程:是一种抽象程度很高的声明式编程范式。
  • 核心思想:
    • 将计算看做是数学函数的求值。
    • 强调通过组合纯函数、避免可变状态和副作用来构建程序。
  • 函数式编程中“函数”的含义:
    • 数学函数:输入到输出的映射,无副作用,行为可预测。
    • 一等公民(First-Class Citizen):函数可以像变量一样被传递、返回和存储。
      • 允许把函数本身作为参数传入另一个函数,还允许返回一个函数。

  • 函数式编程的优势:
    1. 可维护性:无副作用和不可变性减少隐藏的 Bug。
    2. 可测试性:纯函数易于单元测试。
    3. 并发安全:不可变数据天然线程安全。

  • 函数式编程通过纯函数、不可变数据和高阶函数,提供了一种更安全、更简洁的代码组织方式。
    • Java 虽然并非纯函数式语言,但通过 Lambda 和 Stream API 支持函数式风格。
    • 使开发者能够结合面向对象与函数式编程的优势。

1、核心特征 1 – 纯函数(Pure Function)

  • 给定相同输入,总是返回相同输出。
  • 无副作用(不修改外部状态。如:没有全局变量、IO 操作等)。
// 纯函数:无副作用,输出仅依赖输入
// 解释:无论何时调用 add(2,3),结果始终是 5,且不修改任何外部状态。
public static int add(int a, int b) {
    return a + b;
}

2、核心特征 2 – 不可变性(Immutability)

  • 数据一旦创建,不可被修改,任何“修改”操作都生成新数据。
// 不可变类
// 解释:Person 对象一旦创建,属性无法被修改,符合不可变性原则。
public final class Person {
    private final String name; // final 修饰,初始化后不可变
    private final int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 不提供 setter 方法,只有 getter
}

3、核心特征 3 – 高阶函数(Higher-Order Function)

  • 函数可作为参数传递或作为返回值
// 高阶函数:接受函数作为参数
// 解释:processNumbers 接受一个函数参数 processor,对集合中的每个元素应用该函数。
public static List<Integer> processNumbers(
    List<Integer> numbers, 
    Function<Integer, Integer> processor // 函数式接口
) {
    return numbers.stream()
                  .map(processor)
                  .collect(Collectors.toList());
}



// 使用 Lambda 调用
List<Integer> numbers = Arrays.asList(1, 2, 3);
List<Integer> doubled = processNumbers(numbers, n -> n * 2); // [2, 4, 6]

4、核心特征 4 – 声明式风格(Declarative Style)

  • 关注“做什么”而非“如何做”。如:用 filtermap 代替 循环
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// 过滤偶数 -> 平方 -> 求和
// 解释:
//		filter、map、reduce 是高阶函数,接受 Lambda 表达式。
//		无副作用:原始列表 numbers 未被修改。
//		声明式风格:直接描述“过滤偶数、平方、求和”,而不是使用循环实现。
int sum = numbers.stream()
                 .filter(n -> n % 2 == 0)    // 高阶函数:过滤
                 .map(n -> n * n)            // 高阶函数:映射
                 .reduce(0, Integer::sum);   // 高阶函数:规约

System.out.println(sum); // 输出:20 (2² + 4² = 4 + 16)

4、面向对象编程 相比 面向过程编程 的优势


  • 对于大规模复杂程序的开发,程序的处理流程并非单一的一条主线,而是错综复杂的网状结构
    • 面向对象编程比起面向过程编程,更能应对这种复杂类型程序开发
  • 面向对象编程相比面向过程编程,具有更加丰富的特性(封装、抽象、继承、多态)。
    • 利用这些特性编写出来的代码,更加易扩展易复用易维护
  • 从编程语言跟机器打交道的方式的演进规律中,可以总结出:
    • 面向对象编程语言比起面向过程编程语言,更加人性化、更加高级、更加智能

5、Java 中常见的面向过程风格的代码


1、滥用 getter、setter 方法

  • 一个类,无论是否需要,为所有属性都提供了 get / set 方法。

2、滥用全局变量和全局方法

  • 常见的一个项目一个大而全Constants 类,一个大而全Utils 类

  • 如何避免?
  • 1、针对不同的功能,设计不同的 Constants 类、 Utils 类。
    • 如:FileConstants、MysqlConstants 等,FileUtils、StringUtils 等。
  • 2、不单独设计 Constants 常量类,把具体类用到的常量封装定义在该内部
    • 如:RedisConfig 类用到了 Redis 配置相关的常量 ,就直接定义在 RedisConfig 中。
    • 提高了类设计内聚性代码的复用性

3、定义数据和方法分离的类 – 基于贫血模式的开发模式

  • 后端开发常见的分层模型
    • Controller 层负责暴露接口给前端调用、Service 层负责核心业务逻辑,Repository 层负责数据读写
  • 每一层中,又会定义相应的 VO(View Object)、BO(Business Object)、Entity。
    • 一般情况下,VO、BO、Entity 中只会定义数据不会定义数据操作方法
    • 所有操作这些数据业务逻辑定义对应的 Controller 类、Service 类、Repository 类中。
  • 这就是典型的面向过程编程风格
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值