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.这很容易,所以现在你需要的功能将数据从映射Person到PersonDto.可能是这样的:
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使用这样的代码创造奇迹.
经典的并发问题"The Sleeping Barber"可能会很好.
这里有几个例子
http://www.bestinclass.dk/index.clj/2009/09/scala-vs-clojure-round-2-concurrency.html
https://github.com/bitsai/clojure-actors/blob/master/sleeping_barber.clj
| 归档时间: |
|
| 查看次数: |
2043 次 |
| 最近记录: |