# 面向对象与函数式编程

有两种基本的“**编程范式（Programming Paradigms）**”：“**命令式编程（Imperative Programming）**”与“**声明式编程（Declarative Programming）**”.

然而实际中，我们常常讨论的是“**面向对象编程（Object-Oriented Programming）**”与“**函数式编程（Functional Programming）**”，它们分别代表了命令式编程与声明式编程。实际上，命令式编程除了面向对象编程，还包含传统的过程式编程，如 C 语言的通常编程方式；而声明式编程，也包含了逻辑式编程、数学编程及响应式编程等方式。

在这里，简单展示一下面向对象编程与函数式编程的差异。为了易于理解，这里都使用了 Java：

```java
public class Words {
    private Set<String> NON_WORDS = new HashSet<>() {{
        add("the"); add("and"); add("of"); add("to"); add("a");
        add("i"); add("it"); add("in"); add("or"); add("is");
        add("d"); add("s"); add("as"); add("so"); add("but");
        add("be");
    }};

    public Map<String, Integer> wordFreq(String words) {
        TreeMap<String, Integer> wordMap = new TreeMap<>();
        Matcher m = Pattern.compile("\\w+").matcher(words);
        while (m.find()) {
            String word = m.group().toLowerCase();
            if (!NON_WORDS.contains(word)) {
                if (wordMap.containsKey(word)) {
                    wordMap.put(word, wordMap.get(word) + 1);
                } else {
                    wordMap.put(word, 1);
                }
            }
        }
        return wordMap;
    }
 }
```

```java
private List<String> regexToList(String words, String regex) {
    List<String> wordList = new ArrayList<>();
    Matcher m = Pattern.compile(regex).matcher(words);
    while (m.find()) {
        wordList.add(m.group());
    }
    return wordList;
}

public Map<String, Integer> wordFreq(String words) {
    TreeMap<String, Integer> wordMap = new TreeMap<>();
    regexToList(words, "\\w+").stream()
            .map(String::toLowerCase)
            .filter(word -> !NON_WORDS.contains(word))
            .forEach(word -> wordMap.put(
                    word,
                    wordMap.getOrDefault(word, 0) + 1
            ));
    return wordMap;
}
```

可以看到，后者相比于前者的嵌套层级更少。并且它们具有本质上的区别：前者描述了程序工作的具体细节，描述“该怎么做”，而后者描述了程序应该输出什么，通过一个个变换描述“想要得到什么”。

实际上，真正函数式风格的代码要比这里的 Java 代码简洁得多。比如这是一段用 Clojure 编写的，处理一个员工姓名列表的代码：

```clojure
(defn process [list-of-emps]
  (->> list-of-emps
    (filter #(< 1 (count %)))
    (map s/capitalize)
    (interpose ", ")
    (reduce str)))
```

通常认为函数式编程提供了一种比面向对象编程更高阶的抽象方式。在面向对象编程中，我们传递对象，使用对象上的方法来完成某一功能；而在函数式编程中，我们通过组合一系列函数实现某一功能。实际上，这两种方式应该并无明确的好坏之分，而仅仅代表了两种思维方式的差异。

目前普遍的观点认为，对于业务中数据的处理，使用偏函数式编程的模式能够更清晰地表达逻辑。而对于大型程序各部分之间的组织，使用面向对象的思路会更加合适。

不过，许多观点也认为，使用函数式编程同样能够清晰地组织大规模的程序，例如使用“**领域驱动设计（Design Driven Design, DDD）**”，这是一种通用的设计程序的形式，而不仅仅限于某种具体的编程范式，只是人们已经习惯于使用面向对象的思想来组织程序了。

不过，关键是要清楚这两种编程范式并非对立的，而是可以结合使用的。在程序中恰当地使用函数式编程思想，往往能使我们的代码变得更加清晰且易于维护。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gaoge011022.gitbook.io/missing-necessary-knowledge-for-cs-students/ji-chu-zhi-shi/bian-cheng-yu-yan/oop-and-fp.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
