什么是Clojure的好展示?

spa*_*spa 7 clojure

我想开一个关于Clojure的会议.你能推荐一个可以通过Clojure函数编程优雅解决的问题吗?你能指出涵盖这个主题的资源吗?

pon*_*zao 12

使用Clojure的许多论据似乎都与它的并发处理有关,但我不会在这里触及这个问题.

我将列出一些问题,我不得不每周与Java交易,以及我如何在Clojure中解决这些问题.

不变性

在Java中实现不变性非常困难.除了遵循严格的编码实践,您还必须非常谨慎地选择框架和库.另外,作为副作用,您可以编写大量代码来制作干净且可用的API,或者只是强制客户端处理它.

final Person person = personDao.getById(id);
// I would like to "change" the person's email, but no setters... :(
Run Code Online (Sandbox Code Playgroud)

在Clojure中,您可以根据不可变数据结构对数据进行建模,因此默认情况下所有对象都是不可变的,因此Clojure提供了强大的功能,可以在这些结构上运行.

(let [person            (get-by-id person-dao id)
      person-with-email (assoc person :email email)]
  ; Use person-with-email...
Run Code Online (Sandbox Code Playgroud)

转换

在Java中,你有一个域类Person与领域id,name,email,socialSecurityNumber等.您正在创建一个Web服务,用于检索数据库中所有人员的姓名和电子邮件.您不希望公开您的域,因此您创建一个PersonDto包含name和的类email.这很容易,所以现在你需要的功能将数据从映射PersonPersonDto.可能是这样的:

public class PersonPopulator {
    public PersonDto toPersonDto(Person person) {
        return new PersonDto(person.getName(), person.getEmail());
    }

    public List<PersonDto> toPersonDtos(List<Person> persons) {
        List<PersonDto> personDtos = new ArrayList<PersonDto>();
        for (Person person : persons) {
            personDtos.add(toPersonDto(person));
        }
        return personDtos;
    }
}
Run Code Online (Sandbox Code Playgroud)

好吧那不是那么糟糕,但是如果你想在DTO中添加更多数据呢?那么构造函数代码toPersonDto会增长一点,不用担心.如果有两个不同的用例,一个如上,另一个我们只想发送电子邮件怎么办?好吧,我们可以留下name零(坏主意)或者创建一个新的DTO PersonWithEmailDto.因此,我们将创建一个新类,一些用于填充数据的新方法......您可能会看到它的发展方向?

Clojure是一种具有不可变数据结构的动态类型语言,它允许我这样做:

(defn person-with-fields [person & fields]
  (reduce #(assoc %1 %2 (get person %2)) {} fields))

(person-with-fields {:id 1 
                     :name "John Doe"
                     :email "john.doe@gmail.com"
                     :ssn "1234567890"} :name :email)
; -> {:email "john.doe@gmail.com", :name "John Doe"}
Run Code Online (Sandbox Code Playgroud)

并操纵一个人名单:

(map #(person-with-fields % :name :email) persons)
Run Code Online (Sandbox Code Playgroud)

同时向一个人添加临时数据也很容易:

(assoc person :tweets tweets)
Run Code Online (Sandbox Code Playgroud)

这不会破坏任何东西.在Java中,如果你的对象是不可变的,它们可能没有setter,所以你必须编写很多样板来修改一个field(new Person(oldPerson.getName(), oldPerson.getEmail(), tweets)),或者创建一个全新的类.可变对象提供了一个很好的API(oldPerson.setTweets(tweets)),但很难测试和理解.

测试

许多Java代码基于某些状态,即使不需要它也是如此.这意味着您可以模拟此状态,这通常意味着额外的样板,如果您还没有创建具有可测试性的代码,则会变得更难.另一方面,没有模拟的测试通常很慢,并且取决于数据库访问或时间或其他肯定会在您不时失败的事情.

在编写Clojure时,我注意到我实际上并不需要那么多状态.几乎唯一的情况是当我从"外部"检索某些东西时,无论是数据库还是某些Web服务.

摘要

我的代码是一个管道,从一端我获得了一些数据,然后通过过滤,转换或将其与一些其他数据连接,直到它到达管道的末端,然后在管道中更改此数据.在管道内部没有必要真正改变数据,但很多情况下强大的函数和不可变的数据结构是有用的,这就是为什么Clojure使用这样的代码创造奇迹.