web-dev-qa-db-ja.com

「クラスではなくマップを使用してデータを表現する」-リッチヒッキー

Clojureの作成者である このビデオはRich Hickeyによる で、Javaのようにクラスを使用してデータを表すのではなく、マップを使用してデータを表すことをお勧めしています。 APIユーザーが単純にマップとして表されている場合、入力キーが何であるかをどのようにして知ることができるのか、私はそれがどのように良くなることができるか理解していません。

PersonAPI {
    Person addPerson(Person obj);
    Map<String, Object> addPerson(Map<String, Object> personMap);
}

2番目の関数では、APIユーザーは、人を作成するための入力をどのようにして知ることができますか?

19
Emil

Exagg'itive Summary (TM)

あなたはいくつかのものを得ます。

  • プロトタイプの継承とクローニング
  • 新しいプロパティの動的な追加
  • 同じクラスの異なるバージョン(仕様レベル)のオブジェクトの共存。
    • より新しいバージョン(仕様レベル)に属するオブジェクトには、追加の「オプション」プロパティがあります。
  • 古いものと新しいプロパティの内省
  • 検証ルールの内省(以下で説明)

致命的な欠点が1つあります。

  • コンパイラは、スペルミスの文字列をチェックしません。
  • 自動リファクタリングツールは、豪華なものにお金を払わない限り、プロパティキーの名前を変更しません。

、um、introspectionを使用してイントロスペクションを取得できます。これは通常発生します。

  • リフレクションを有効にします。
  • 大きなイントロスペクションライブラリをプロジェクトに追加します。
  • さまざまなオブジェクトのメソッドとプロパティに属性または注釈を付けます。
  • イントロスペクションライブラリに魔法をかけてもらいましょう。

つまり、FPとのインターフェースが不要になった場合は、Rich Hickeyのアドバイスに従う必要はありません。

最後に、ただし重要ではありませんが、Stringをプロパティキーとして使用するのが最も簡単ですが、Stringsを使用する必要はありません。多くのレガシーシステムAndroid™を含むは、フレームワーク全体で整数IDを広範囲に使用して、クラス、プロパティ、リソースなどを参照します。

AndroidはGoogle Inc.の商標です。


両方の世界を幸せにすることもできます。

Javaの世界では、通常どおりゲッターとセッターを実装します。

FP世界の場合、

  • Object getPropertyByName(String name)
  • void setPropertyByName(String name, Object value) throws IllegalPropertyChangeException
  • List<String> getPropertyNames()
  • Class<?> getPropertyValueClass(String name)

これらの関数の内部では、はい、醜いコードですが、IDEプラグインがあり、それを埋めてくれます...ええと、スマートプラグインreads yourコード。

Java側は通常どおりパフォーマンスが向上します。コードのその醜い部分を使用することはありません。Javadocから非表示にすることもできます。

FP世界の側は、彼らが望むどんな「リート」なコードも書くことができます、そして彼らは通常、コードが遅いことについてあなたに怒鳴りません。


一般に、オブジェクトの代わりにマップ(プロパティバッグ)を使用することは、ソフトウェア開発では一般的です。関数型プログラミングや特定の種類の言語に固有のものではありません。特定の言語の慣用的なアプローチではないかもしれませんが、それを必要とする状況があります。

特に、シリアライゼーション/デシリアライゼーションでは同様の手法が必要になることがよくあります。

「オブジェクトとしてのマップ」に関するいくつかの一般的な考え。

  1. そのような「オブジェクトとしてのマップ」を検証するための関数を提供する必要があります。違いは、「オブジェクトとしてマップ」により、より柔軟な(制限の少ない)検証基準が可能になることです。
  2. 「オブジェクトとしてマップ」に追加フィールドを簡単に追加できます。
  3. 有効なオブジェクトの最小要件の仕様を提供するには、次のことを行う必要があります。
    • マップで予想される「最低限必要な」キーのセットをリストします
    • 値を検証する必要があるキーごとに、値検証関数を提供します
    • 複数のキー値をチェックする必要がある検証ルールがある場合は、それも提供します。
    • メリットは何ですか?この方法で仕様を提供することは内省的です。最小限必要なキーのセットをクエリし、各キーの検証関数を取得するプログラムを作成できます。
    • OOPでは、これらすべてが「カプセル化」という名前のブラックボックスにまとめられます。マシンが読み取り可能な検証ロジックの代わりに、呼び出し元は人間が読み取り可能な「APIドキュメント」のみを読み取ることができます(幸い、存在する場合)。
12
rwong

それは彼が何を話しているのかを本当に知っている誰かによる素晴らしい話です。読者には全体を見ることをお勧めします。長さはわずか36分です。

彼の主なポイントの1つは、単純であることは後で変更の機会を開くことです。 Personを表すクラスを選択すると、指摘したとおり、静的に検証可能なAPIを作成することですぐにメリットが得られますが、それには、機会を制限したり、変更や再利用のコストを増やしたりするコストが伴います。

彼のポイントは、クラスを使用することは合理的な選択かもしれないが、それはコストを完全に意識することを伴う意識的な選択であるべきであり、プログラマーは伝統的にそれらを考慮に入れることはもちろん、それらのコストに気づくという非常に貧弱な仕事をします。その選択は、要件が大きくなるにつれて再評価する必要があります。

以下は、Personオブジェクトのリストを使用するよりもマップのリストを使用するほうが簡単な可能性があるいくつかのコード変更(1つまたは2つは講演で説明されています)です。

  • 人をRESTサーバーに送信します。(Mapのプリミティブを送信可能な形式にするために作成された関数は、再利用性が高く、ライブラリで提供される場合もあります。APersonオブジェクトは、同じジョブを実行するためにカスタムコードを必要とする可能性があります)。
  • リレーショナルデータベースのクエリから人のリストを自動的に作成します。 (繰り返しになりますが、1つの汎用的で再利用可能な関数です)。
  • 人を表示および編集するためのフォームを自動的に生成します。
  • 一般的な関数を使用して、学生と従業員のように非常に不均一な個人データを操作します。
  • 特定の郵便番号に居住するすべての人のリストを取得します。
  • そのコードを再利用して、特定の郵便番号に含まれるすべてのビジネスのリストを取得します。
  • 他のクライアントに影響を与えずに、顧客固有のフィールドを個人に追加します。

私たちは常にこの種の問題を解決し、そのためのパターンとツールを用意していますが、最初に単純でより柔軟なデータ表現を選択することで作業が簡単になるかどうかについて考えることはめったにありません。

9
Karl Bielefeldt
  • データがほとんどまたはまったく動作せず、変化する可能性のある柔軟なコンテンツがある場合は、マップを使用します。 IMO(N-フィールド、Nセッター、Nゲッターを含む Anemic Domain Model で構成される典型的な「javabean」または「データオブジェクト」)は時間の無駄です。ファンシースマンシークラスでそれを包むことによって、美化された構造体で他の人を感動させようとしないでください。正直に言うと 意図を明確にする で、マップを使用します。 (または、ドメインに意味がある場合は、JSONまたはXMLオブジェクト)

  • データに重要な実際の動作がある場合、a.k.aメソッド( Tell、Do n't Ask )の場合、クラスを使用します。そして、本当のオブジェクト指向プログラミングを使うために背中を軽くたたいてください:-)。

  • データに必須検証動作と必須フィールドが多数ある場合は、クラスを使用します。

  • データに適度な量の検証動作がある場合、それは境界線です。

  • データがプロパティ変更イベントを発生させる場合、それは実際にはMapを使用する方が簡単ではるかに面倒ではありません。ちょっとしたサブクラスを書いてください。

  • Mapを使用する場合の主な欠点の1つは、ユーザーが値をStrings、ints、Foosなどにキャストする必要があることです。これが非常に煩わしく、エラーが発生しやすい場合は、クラスを検討してください。または、関連するゲッターでMapをラップするヘルパークラスを検討してください。

4
user949300

mapのAPIには2つのレベルがあります。

  1. マップのAPI。
  2. アプリケーションの規約。

APIは、慣例によりマップに記述できます。たとえば、ペア:api api-validateをマップに配置したり、:api-foo validate-fooを規則にしたりできます。地図にはapi api-documentation-linkも格納できます。

規則を使用すると、プログラマーは、マップとして実装された「タイプ」間のアクセスを標準化するドメイン固有の言語を作成できます。 (keys map)を使用すると、実行時にプロパティを決定できます。

マップには魔法はなく、オブジェクトにも魔法はありません。すべて発送です。

0
ben rudgers