0

このような複雑なオブジェクトで構成されているオブジェクトがあります

class ObjectA {   
  int cool
  Object1 b   
  Object2 b 
}


class Object1 {   
  int go
  String do 
}

要件は、ファイルからCSVデータをロードし、それを上記のオブジェクトのインスタンスに割り当てることです。Grails CSVプラグインを使用しており、ファイルからCSVデータを取得できます。各行は、一意のオブジェクトインスタンスの値を含むMAPです。マップは次の形式です。

cool: 1, object1go: 3, object1do: 'hello', object2hm: 'world'

私の質問は、多くの解析を行うことなく、クラス内のデータメンバー(つまり)に「 object1go」と「 」を効率的に渡すにはどうすればよいかということです。object1doObject1ObjectA

4

3 に答える 3

2

これがGrailsでどれだけうまく機能するかはわかりませんが、Groovyでは機能します。

class ObjectA {
    String name
    Object1 object1
    Object2 object2

    ObjectA(java.util.Map attrs) {
    attrs.each { key, val ->
        this.class.declaredFields.each {
            if (!it.synthetic) {
                def className = it.type.name.toLowerCase()
                def localVar = it.name
                if (key =~ /^${className}/) {
                    def realKey = key.replaceAll("^${className}", "")

                    if (!this."${localVar}") {
                        this."${localVar}" = Class.forName("${className.capitalize()}", true, this.class.classLoader).newInstance()
                    }

                    this."${localVar}"."${realKey}" = val.replaceAll("'", "")
                } else {
                    try {
                        this."${key}" = val.replaceAll("'", "")
                    } catch (MissingPropertyException e) { }
                }
            }
        }
    }
    }
}

class Object1 {
    String foo
    String bar
}

class Object2 {
    String foo
    String bar
}


def data = "name: 'dan', object1foo: 'food', object1bar: 'baz', object2foo: 'foor', object2bar: 'xanax'"
def attrs = data.split(',').inject([:]) { map, keyPair -> 
    keyPair.split(':').with { map[it[0].trim()] = it[1].trim() }
    map 
}

def a = new ObjectA(attrs)

assert a.name == 'dan'
assert a.object1 instanceof Object1
assert a.object2 instanceof Object2
assert a.object1.foo == 'food'
assert a.object2.foo == 'foor'
assert a.object1.bar == 'baz'
assert a.object2.bar == 'xanax'

それが役に立てば幸い。:-)

于 2012-04-10T21:11:59.697 に答える
1

(これは一緒にスローされます。大幅に拡張/カプセル化できます。)

デフォルトの ctor はマップを取得するため、埋め込みオブジェクトの名前プレフィックスを吸い取って、各オブジェクトに必要なパラメーター マップを作成するのが最も簡単です。

class Object1 {   
  int go
  String s
  String toString() {
    "<<${super.toString()}: go=${go}, s=${s}>>"
  }
}

class ObjectA {   
  int cool
  Object1 b   
  String toString() {
    "<<${super.toString()}: cool=${cool}, b=${b}>>"
  }
}

params = [cool: 1, object1go: 3, object1s: 'hello']

// Params for embedded object.
o1params = params.findAll { it.key.startsWith("object1") }

// Embedded object's property names (the above map minus the prefix).
tmp1 = o1params.collectEntries { k, v -> [(k[7..-1]): v] }

// "Parent" object's params.    
oaparams = params - o1params

oa = new ObjectA(oaparams + [b: new Object1(tmp1)])
println oa.toString()

これを強化する方法はたくさんありますが、どれも非常に簡単で簡単です。たとえば、"object1"名前と長さをハードコーディングしました。これは、汎用メソッドや DSL などにまとめることができます。プロパティ名は、クラスから直接取得できます。これをよりきれいにする方法はたくさんあります。

ただし、CSV からマップ名を変更できる場合は、JSON などの中間ステップを検討し、代わりにそれから逆シリアル化するだけです。

于 2012-04-10T16:42:50.460 に答える
0

私は私の質問に答えています。これまでに見つけた最も簡単な方法は、ヘッダー列をクラス内のカプセル化されたデータ メンバーにマップすることです。例: Main クラスがObjectB(名前は roll) をデータ メンバーとして持っているとします。次に、CSV/XLS ファイルで、ヘッダー列にroll.number. 解析中にファイル行がマップに変換されると、このマップをコンストラクターに直接渡すことができ、それに応じてすべての値が割り当てられます。つまり、すべての複雑な子オブジェクトは、ファイルで定義された値で初期化されます。

私はこのテクニックを実装しましたが、それは魅力のように機能します。

于 2012-04-17T15:49:24.197 に答える