実行時にクラスにフィールドを追加する-デザインパターン


15

顧客が、CMSのeショップで製品に新しいプロパティ(色など)を追加する可能性を望んでいると想像してください。

プロパティをフィールドとして持つ代わりに:

class Car extends Product {
   protected String type;
   protected int seats;
}

あなたはおそらく次のようなことをすることになります:

class Product {
   protected String productName;
   protected Map<String, Property> properties;
}

class Property {
   protected String name;
   protected String value;
}

つまり、既存の型システムの上に独自の型システムを作成します。これは、ドメイン固有の言語を作成しているように見えるかもしれない、またはできないように思えます。

このアプローチは既知の設計パターンですか?問題を別の方法で解決しますか?ランタイムにフィールドを追加できる言語がありますが、データベースはどうですか?上記のように列を追加/変更するか、何かを使用しますか?

お時間をいただきありがとうございます:)。



使用している言語はわかりませんが、C#の場合は、基本的に製品で行っているような辞書にKVPを保存し、プロパティに直接追加することなくプロパティを追加できる動的タイプを使用できますコレクションとしてのコレクション。ただし、強い型付けはありません。あなたがデザインパターンを要求したことは知っていますが、それらを使用するのに複雑なものは必要ないと思います。msdn.microsoft.com/en-us/magazine/gg598922.aspx
トニー14

Tony:ここではJavaを使用していますが、疑似コードと考えてください:)。C#では、その動的オブジェクトをデータベースに永続化できますか?データベースは事前にデータの構造を知る必要があるので、私はそれを疑います。
フィリップ14

ある国家最新デザインパターンオブジェクトを作るラギャング・オブ・四、表示されて変更するタイプクラスを実行時には。他の選択肢はオブザーバーデザインパターンかあるプロキシデザインパターン
ニコスM.

1
地図データ型を使用しないのはなぜですか?DBでは、パフォーマンスを要求しない場合、{id} + {id、key、value}として表される場合があります。
雨の影14年

回答:


4

おめでとう!プログラミング言語/タイプシステムグローブを一周して、出発地から世界の反対側に到着しました。動的言語/プロトタイプベースのオブジェクトランドの境界に到着しました!

多くの動的言語(JavaScript、PHP、Pythonなど)では、実行時にオブジェクトプロパティを拡張または変更できます。

これの極端な形式は、SelfやJavaScriptのようなプロトタイプベースの言語です。厳密に言えば、クラスはありません。継承を使用して、クラスベースのオブジェクト指向プログラミングのように見えることを実行できますが、JavaやC#などのより明確に定義されたクラスベースの言語と比較して、ルールは大幅に緩和されます。

PHPやPythonのような言語は、その中間に存在します。定期的で慣用的なクラスベースのシステムがあります。ただし、JavaScriptにはないいくつかの制限(「組み込み型を除く」など)にかかわらず、オブジェクト属性は実行時に追加、変更、または削除できます。

このダイナミズムの大きなトレードオフはパフォーマンスです。言語がどれだけ強くまたは弱く型付けされているか、または機械語にコンパイルできるかを忘れてください。動的オブジェクトは、単純な構造ではなく、柔軟なマップ/辞書として表現する必要があります。これにより、すべてのオブジェクトアクセスにオーバーヘッドが追加されます。一部のプログラムはこのオーバーヘッドを削減するために非常に長くなります(たとえば、Pythonでのファントムkwarg割り当てとスロットベースのクラスを使用)が、余分なオーバーヘッドは通常、コースと入場料に見合うだけです。

設計に戻って、クラスのサブセットに動的プロパティを持つ機能を移植しています。AはProduct、変数の属性を持つことができます。おそらく、またはは、そうInvoiceするOrderことはできませんでした。悪い方法ではありません。厳格で統制のとれた言語と型システムを維持しながら、必要な場所にバリエーションを持たせる柔軟性を提供します。欠点は、これらの柔軟なプロパティを管理することです。おそらく、ネイティブの属性とは少し異なるように見えるメカニズムを介して管理する必要があります。p.prop('tensile_strength')のではなくp.tensile_strength、例えば、とp.set_prop('tensile_strength', 104.4)いうよりp.tensile_strength = 104.4。しかし、私はPascal、Ada、C、Java、さらには非標準の属性タイプに対してまさにそのようなゲッターセッターアクセスを使用する動的言語でさえ、多くのプログラムを使用して構築しました。アプローチは明らかに実行可能です。

ところで、静的型と非常に多様な世界との間のこの緊張は非常に一般的です。特にリレーショナルおよび事前リレーショナルデータストアのデータベーススキーマを設計するときに、類似の問題がよく見られます。想定されるすべてのバリエーションの結合を含むか定義するのに十分な柔軟性を備えた「スーパーロー」を作成し、それらのフィールドに含まれるデータを詰めることで対処する場合があります。WordPressのwp_postsテーブルには、例えば、などの分野があるcomment_countping_statuspost_parentおよびpost_date_gmtいくつかの状況下でのみ興味深いものです、実際には、多くの場合、空白を行くことを。別のアプローチは、のような非常に予備の正規化されたテーブルwp_optionsです。Propertyクラス。より明示的な管理が必要ですが、その中の項目が空白になることはめったにありません。オブジェクト指向データベースとドキュメントデータベース(MongoDBなど)は、オプションを変更するのに簡単に対応できる場合がよくあります。これは、属性を自由に作成および設定できるためです。


0

私は2セントの質問が好きです。

2つのアプローチは根本的に異なります。

  • 最初のものはオブジェクト指向で強く型付けされていますが、拡張可能ではありません
  • 2番目は弱く型付けされています(文字列はすべてをカプセル化します)

C ++では、多くの人がboost :: variantの std :: mapを使用して、両方の組み合わせを実現します。

問題点: C#などの一部の言語では、型を動的に作成できることに注意してください。これは、メンバーを動的に追加するという一般的な問題の素晴らしい解決策になる可能性があります。ただし、コンパイル後に型を「変更/追加」すると型システム自体が破損し、「変更」型はほとんど役に立たなくなります(たとえば、そのような追加されたプロパティにアクセスするにはどうすればよいでしょうか?各オブジェクトを体系的に反映する...純粋な動的言語で終わる_「動的」.NETキーワードを参照できます)


実行時に継ぎ目を作成することは興味深いが、あまりにもエキゾチックです(私はJavaでプログラミングしています)。オブジェクトをデータベースに保存したい場合、そのような解決策は機能しません。私が提案した弱い型付けのソリューションは、データベースに簡単に保存できます。
フィリップ14

0

実行時に型を作成することは、単に抽象化レイヤーを作成するよりもはるかに複雑に聞こえます。システムを分離するための抽象化を作成することは非常に一般的です。

私の練習から例を示しましょう。モスクワ取引所には、Plaza2と呼ばれるトレーディングコアとトレーダーのAPIがあります。トレーダーは、財務データを処理するプログラムを作成します。問題は、このデータが非常に巨大で複雑であり、変更に非常にさらされていることです。新しい金融商品が導入された後、または清算のルールが変更された後に変更される可能性があります。将来の変化の性質は予測できません。文字通り、それは毎日変わる可能性があり、貧しいプログラマーはコードを編集して新しいバージョンをリリースし、怒っているトレーダーはシステムを修正する必要があります。

明らかな決定は、抽象化の背後にすべての金融地獄を隠すことです。よく知られているSQLテーブルの抽象化を使用しました。トレーダーのソフトウェアがスキーマを動的に解析し、システムと互換性があるかどうかを調べることができるのと同じように、コアの最大部分は任意の有効なスキーマで動作できます。

例に戻りますが、通常は、いくつかのロジックの前に抽象言語を作成します。「プロパティ」、「テーブル」、「メッセージ」、さらには人間の言葉でさえありますが、このアプローチの欠点に注意してください。

  • 解析と検証のためのコードが増えました(そして、より多くの時間の経過)。コンパイラが静的型付けで行ったことはすべて、実行時に実行する必要があります。
  • メッセージ、テーブル、またはその他のプリミティブの詳細なドキュメント。すべての複雑さは、コードからある種のスキーマまたは標準になります。上記の金融地獄スキーマの例を次に示します。http : //ftp.moex.com/pub/FORTS/Plaza2/p2gate_en.pdf(数十ページの表)

0

このアプローチは既知の設計パターンですか?

XMLおよびHTMLでは、これらはノード/要素の属性になります。また、拡張プロパティ、名前/値のペア、およびパラメーターと呼ばれるものも聞きました。

問題を別の方法で解決しますか?

それが私が問題を解決する方法です、はい。

ランタイムにフィールドを追加できる言語がありますが、データベースはどうですか?

ある意味では、データベースはJavaに似ています。pesudo-sqlの場合:

TABLE products
(
    product_name VARCHAR(50),
    product_id INTEGER AUTOINCREMENT
)

TABLE attributes
(
    product_id INTEGER,
    name VARCHAR(50),
    value VARCHAR(2000)
)

これはJavaに対応します

class Product {
   protected String productName;
   protected Map<String, String> properties;
}

Mapは名前をキーとして保存するため、Propertyクラスは必要ありません。

上記のように列を追加/変更するか、何かを使用しますか?

カラムの追加/変更を試しましたが、それは悪夢でした。それはできますが、物事は同期しなくなり、私はそれがうまく機能することはありませんでした。上で概説したテーブル構造は、はるかに成功しています。あなたがさんによる検索と注文を行う必要がある場合は、各データタイプ(テーブルを属性を使用して検討しdate_attributescurrency_attributesなど)や製品テーブル内の古き良きデータベース列のような特性のいくつかを追加します。レポートは、多くの場合、サブテーブルよりもデータベースの列に書く方がはるかに簡単です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.