Clojure defprotocol作为表达式问题的解决方案 [英] Clojure defprotocol as a solution to the expression problem

查看:140
本文介绍了Clojure defprotocol作为表达式问题的解决方案的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在The Joy of Clojure一书中, defprotocol 是作为表达式问题的解决方案提供的 -

In the book "The Joy of Clojure", defprotocol is offered as a solution to the expression problem -- "the desire to implement an existing set of abstract methods for an existing concrete class without having to change the code that defines either."

给定的示例如下:

(defprotocol Concatenatable
  (cat [this other]))

(extend-type String
  Concatenatable
  (cat [this other]
    (.concat this other)))

(cat "House" " of Leaves")
;=> "House of Leaves"

(extend-type java.util.List
  Concatenatable
  (cat [this other]
    (concat this other)))

(cat [1 2 3] [4 5 6])
;=> (1 2 3 4 5 6)

建议这不可能用Java ,但是如何与以下不同呢?

It is suggested that this is not possible in a language like Java, but how is it different than the following?

public class Util {
  public static String cat(final String first,
                           final String second) {
    return first.concat(second);
  }

  public static <T> List<T> cat(final List<T> first,
                                final List<T> second) {
    final List<T> list = new List<T>(first);
    list.addAll(second);
    return list;
  }
}

毕竟,两者的使用方式类似:

After all, both are used similarly:

(cat "House" " of Leaves")
Util.cat("House", " of Leaves");

Clojure函数 cat 不是在 String List 类上的方法用于接受 String 列表参数的非独立函数

The Clojure function cat is not a method on the String and List classes, but rather an independent function that is overloaded to accept either String or List arguments.

虽然我真的很喜欢Clojure,但我不明白这个结构的优势。

Although I really like Clojure, I don't understand the claims of superiority for this construct.

推荐答案

好的。你发布这个 cat Java库,以大声疾呼,大家下载它。这太棒了,我想让我自己的 TVCommercial 类型可以连接,所以我可以发送它到你的库的操作对可连接对象的位。

Okay. You release this cat Java library to much fanfare, and everyone downloads it. It's so great I want to make my own TVCommercial type be concatenable so that I can send it to bits of your library that operate on concatenable objects.

但我不能,因为你调用 Util.cat(obj1,obj2),没有重载 TVCommercial 。我不能扩展你的代码来处理我的类型,因为我不拥有你的代码。

But I can't, because you call Util.cat(obj1, obj2), which has no overload for TVCommercial. I can't extend your code to handle my types, because I don't own your code.

你可以定义Concatenable作为接口来解决这个问题: p>

You can define Concatenable as an interface to address this problem:

interface Concatenable {
  Concatenable cat(Concatenable other);
}

但现在我不能写一个类是连续的.Dunno,一个AnimalHandler,处理 cat 。 Clojure的协议通过分散调度函数和实现来解决这两个问题:它们遍布整个地方,而不是在一个单一的位置。在Java中,您可以在以下选项之间进行选择:

But now I can't write a class which is both Concatenable and...I dunno, an AnimalHandler, that handles cats. Clojure's protocols solve both problems by decentralizing the dispatch functions and implementations: they live all over the place, rather than in some single location. In Java, you choose between:


  • 将所有类型的调度分配到单个开关/大小写或重载方法

  • 定义一个强制使用具有特定名称的方法的接口

Clojure基本上是后者, em>命名空间名称,没有与认为 cat 是一个好的函数名称的其他协议冲突的危险。

Clojure basically does the latter of these, but because it uses namespaced names, there's no danger of conflict with other protocols that think cat is a good function name.

这篇关于Clojure defprotocol作为表达式问题的解决方案的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆