4

Clojure でプロパティとメソッドを使用してオブジェクトを作成したいのですが、gen-class と proxy で必要な作業を実行できることを読みましたが、その実装は非常にわかりにくいものです。

AOT コンパイル手順を回避するためにプロキシを使用したいのですが、それについて読みました。

これがClojureでやりたいことです

Java コード:

public class MyClass {
    public float myFloat;

    MyClass( float _myFloat ) {
        myFloat = _myFloat
    }

    public void showNumber() {
        println( myFloat );
    }
}

プロキシを使用してそのコードを Clojure に変換するのに苦労しています。


アップデート:

私の目的には deftype の方が適しているようですが、まだその実装に苦労しています

ここに私のClojureコードがあります:

(deftype Particle [x y]
  Object
  (render [this]
    (no-stroke)
    (fill 200 30 180)
    (ellipse x y 200 200)))

どのプロトコルを使用すればよいかわからないプロトコルを指定する必要があるため、Java クラスのようなオブジェクトを作成しようとしてオブジェクトを使用していますが、次のエラー メッセージが表示されます。

インターフェイスにないメソッドを定義できません: render

それが役立つ場合、私はClojureの処理ポートであるクイルを使用しています


更新 2:

OK、機能する defprotocol と deftype の組み合わせを取得することができましたが、方法を理解する必要があることがもう 1 つあります。それは、メンバー変数またはプロパティをクラスに追加することです。これが私の clojure コードです。

(defprotocol ParticleProtocol
  (update [this])
  (render [this]))

(deftype Particle [position]
  ParticleProtocol
  (update [this])
  (render [this]
    (no-stroke)
    (fill 200 30 180)
    (ellipse (.x position) (.y position) 20 20)))

このオブジェクトに、半径などのいくつかの変数を追加したいと思いますが、何かアイデアはありますか?

4

2 に答える 2

3

Clojure でこれを行うよりもdeftype(またはおそらく) の方が優れていることに同意しますが、すべての可能性を検討するには、最後に私のコメントを参照してください。defrecordproxy

UPDATE 2の後の質問について。

arglist で指定することにより、レコードに「プロパティ」を追加できます。

(deftype Particle [position radius prop3 prop4]
   ...
 )

Clojure の型は不変であるため、エンティティの作成後にプロパティを設定するという概念はありません。一部のプロパティが省略可能である場合は、次のようなヘルパー「ファクトリ」メソッドを作成することをお勧めします。

(defn make-particle 
  ([position] (Particle. position nil nil nil))
  ([position radius] (Particle. position radius nil nil))
  ;; etc. add more here as needed
  )

考慮すべきオプションは、タイプを完全に削除して、必要な「プロパティ/フィールド」が含まれているマップを使用することです。型は、抽象化を実装する必要がある場合に役立ちます。ParticleProtocol について - それが提供する価値は何ですか? プロトコルはポリモーフィズムを実現する方法を提供することを目的としていますが、このプロトコルを複数実装する予定はありますか?

Chas Emerickは、Clojure でデータ型を選択する方法の詳細なフローチャートを作成しました。-形/


[マップの実装例を示す更新] :

「プロパティ」を使用してマップを作成し、そのプロパティを取得するには、次のようにします。

(def mymap {:myfloat 3.1415926})
(println "myfloat has value:" (:myfloat mymap))

「レンダリング」機能などの追加機能を提供するには、目的のキーを持つマップを受け入れる fn を作成するだけです。

;; the details are bogus, just showing the syntax
(defn render [m]
  (no-stroke)
  (fill (:radius m) (:position m))
  (do-something-else (:position m)))      

の場合update、パーティクル マップの値を更新する場合は、既存のマップを更新するのではなく、新しいマップを作成する必要があります。

(def myparticle {:position 100 :radius 25})

(defn change-pos [particle-map new-pos]
  (assoc-in particle-map [:position] new-pos))

(let [new-particle (change-pos myparticle 300)]
  (println new-particle))
;; prints out {:position 300 :radius 25}
;; orig myparticle still has value {:position 100 :radius 25}

;; or do it directly
(println (assoc myparticle :position 300))
;; prints out {:position 300 :radius 25}
于 2013-03-17T21:50:28.383 に答える
1

position次のように、の横に「変数」を追加できます。

(deftype Particle [position radius]
   ...
  )

positionradius実際には変数ではなく、属性に似ていfinalます。それらを「変化させる」必要がある場合は、次のようにアトムを格納する必要があります。

(Particle. (atom (Position. 3 4)) (atom 5.0))

しかし、オブジェクトとクラスの観点から考えるのをやめて、関数と不変のデータ構造で考え始めるように、@m0skit0 のアドバイスに本当に耳を傾けるべきです。

于 2013-03-17T21:46:24.443 に答える