2012-01-31 4 views

Trả lời

8

Có hai phương pháp cơ bản:

  1. Reflection:

    (clojure.lang.Reflector/invokeConstructor Klass (to-array [arg ...])) 
    

    chậm, nhưng hoàn toàn năng động.

  2. Giải nén các đối số trước:

    (let [[arg1 arg2 ...] args] 
        (Klass. arg1 arg2 ...)) 
    

    ((Klass. ...) là cách thành ngữ viết (new Klass ...), nó được chuyển đổi sang các hình thức sau lúc mở rộng vĩ mô.)

    này sẽ nhanh hơn nếu trình biên dịch có thể suy ra mà constructor sẽ được sử dụng (có thể bạn sẽ cần phải cung cấp gợi ý loại thích hợp - sử dụng (set! *warn-on-reflection* true) để xem nếu bạn đã có nó đúng).

Cách tiếp cận thứ hai là, tất nhiên, hơi khó sử dụng. Nếu bạn dự định xây dựng rất nhiều Klass trường hợp tại nhiều vị trí trong mã của mình, bạn có thể viết một chức năng nhà máy thích hợp. Nếu bạn mong đợi để đối phó với nhiều lớp học theo cách này, bạn có thể tóm tắt đi quá trình xác định các chức năng máy:

(defmacro deffactory [fname klass arg-types] 
    (let [params (map (fn [t] 
         (with-meta (gensym) {:tag t})) 
        arg-types)] 
    `(defn ~(with-meta fname {:tag klass}) ~(vec params) 
     (new ~klass [email protected])))) 

Cuối cùng, nếu quá trình xác định các chức năng nhà máy riêng của mình cần phải được hoàn toàn năng động, bạn có thể làm điều gì đó giống như cách tiếp cận thứ hai của Chouser là this question: xác định một hàm thay vì macro và có nó eval một cái gì đó giống như cú pháp được trích dẫn ở dạng (defn ...) ở trên (cú pháp được trích dẫn = với backtick ở phía trước nó; tôi không chắc chắn cách bao gồm backtick theo nghĩa đen trong bài đăng SO), ngoại trừ bạn sẽ muốn sử dụng fn thay vì defn và có thể bỏ qua fname. Các cuộc gọi đến trình biên dịch sẽ tốn kém, nhưng hàm trả về sẽ thực hiện như bất kỳ hàm Clojure nào; xem câu trả lời nói trên của Chouser để có một cuộc thảo luận dài hơn một chút.

Vì mục đích hoàn chỉnh, nếu bạn đang sử dụng Clojure 1.3 trở lên và lớp Java liên quan thực sự là bản ghi Clojure, thì chức năng nhà máy vị trí sẽ được tạo dưới tên ->RecordName.