web-dev-qa-db-ja.com

フィールド変数とメソッド変数

ちょっと質問があります。

class DatabaseHelper
{
    Database db;
    String defaultShema;

    public DatabaseHelper(Database db, String defaultSheme)
    {
        this.db = db;
        this.defaultShema = defaultShema;
    }

    public void databaseOperation1(String selectData, String FromData, String whereData)
    {
        // uses db and defaultShema
    }

    public void databaseOperation2(Database db, String shema, String selectData, String FromData, String whereData)
    {
        // uses parameter db and parameter shema
    }
}

操作1を使用する場合、フィールド変数dbとdefaultShemaを使用します

しかし、特別なケースがある場合はどうすればよいですか。 defaultShemaまたはdefault dbを使用したくない場合。

その場合、私は新しいDatabaseHelperを作成する必要があります。

また、操作メソッドをそれぞれ異なるdb/defaultShema変数で1000回呼び出したい場合は、一時的なDatabaseHelperオブジェクトを1000個インスタンス化する必要があります。

このパターンのように

new object(...).doAction(); //after that delete

だから私はoperation2を持っていますが、これはサラウンドクラスからの状態が何もないまで使用量が少なくなります。ここでは、何千もの意味のないDatabaseHelperのインスタンスを作成する必要はありません。しかし、おそらくmethod-parameter-setからdbとdefaultSchemaの両方が使用されている場合、このメソッドは静的メソッドとして存在することもできます。しかし、多分私はパラメータセットからそれらのうちの1つだけを使い、クラスのフィールドセットからもう1つを使いたいです。

だからここに私の質問、いつフィールドに変数を作成する必要がありますか、いつメソッドパラメータに?多分ほとんどの場合、selectDataは同一です。だから私はフィールドにそのパラメーターを作成します。

しかし、私は他のメソッド、たとえば挿入メソッドがそのフィールドを必要としないという問題があります->不必要な内部クラスの依存関係。

ここではデータベースの例を使用しました。しかし、問題はこのような他のクラスと非常に共通していると思います。

常に操作2を使用する場合、クラスはもう必要ありません->静的メソッドしかありません。

しかし、メソッド1のような操作1を使用する場合は、フィールドに対して行う必要がある変数を決定する必要があります。しかし、どっち?

そして、私がフィールドに対して行うもの、場合によっては、それらをデフォルトモードで使用したくない場合があります。それらを変更したいので

しかし、私は次のことはナンセンスだと思います:

String tmp=db.getDefaultSchema();
db.changeStateOfDefaultSchema("XYZ");
db.databaseOperation1(...);
db.changeStateOfDefaultSchema(tmp);

//OR
new DatabaseHelper(..., "XYZ").databaseOperation1(...);
//GC -> delete of that tmp DatabaseHelper

では、クラスをどのように設計すればよいですか?どの変数をフィールドに作成し、どの変数をメソッドパラメーターに作成するか。各変数を後で変更できる柔軟性を持たせる場合はどうすればよいですか。私がまだ知らない場合、クライアントが頻繁に変更しなければならない変数とそれほど頻繁ではない変数。

2
Robin Kreuzer

考慮すべき点がいくつかあります。これらは、フィールドまたはメソッドパラメータのどちらを使用するかを決定するのに役立ちます。

  • 値は同様の呼び出しの間で共有されるべきですか?
    「はい」の場合、それらをフィールドにして、パラメータとして毎回渡さないでください。
    この場合、フィールドを使用することで繰り返しを避け、誤った値を誤って使用することを防ぎます。
  • 2つ(またはそれ以上)の値は密接に関連していますか(それらは概念を形成していますか)?
    はいの場合、
    • 発信者はこの概念ですか?
      発信者がこの概念でない場合は、値フィールドを作成します。 これは呼び出しコードでより高いレベルの抽象化を使用しているため、単一責任の原則を遵守するのに役立ちます。値の誤った組み合わせの使用を防ぐのに役立ちます。
  • (すべての呼び出しサイトで)オブジェクトインスタンスを作成し、フィールドを設定(コンストラクターまたはプロパティを介して)し、同じメソッドを呼び出してから、その間に属する他のロジックなしでオブジェクトを破棄していますか?
    「はい」の場合、メソッドパラメータを使用します。 Vector Zitaには優れた点があります。オブジェクトを作成し、そのフィールドを設定し、すぐに1回使用するだけでは無駄です。私見ですが、コードの読者に与える認識の負担は、追加の計算よりも悪いものです。

パラメータを介してすべての入力を受け取る静的メソッドは、他のメソッドの副作用から隔離されているため、テストが簡単です。また、それ自体が副作用を引き起こす可能性も低くなります。
両方を提供し、インスタンスメソッドを静的メソッドに転送することで、静的メソッドのテスト容易性とインスタンスメソッドのカプセル化の利点を組み合わせることができます。

値をオブジェクトのフィールドに結合することを選択した場合は、値(例ではdatabaseおよびschema)と操作(dabaseOperation1)は同じクラスに属しているか、オペレーションが値オブジェクトをパラメーターとして受け入れる必要があります。*は...Helper- classは、実際にはあまり関係のない手順のバッグで、それよりも適切な場所が見つかりませんでしたか?
「はい」の場合、それらのいくつかを首尾一貫したクラスに移動することで改善が見られます。 * DatabaseHelperのメソッド(のサブセット)とフィールドdatabaseおよびschemaは一貫した単位を形成しますか?そして、操作はdatabaseおよびschemaオブジェクトが実行できる何かとして意味がありますか?はいの場合、フィールドと(のサブセット)フィールドを結合します。

databaseschemaパラメータのようなものを使用するフライウェイトパターンを調べてください。特に、フライウェイトパターンをいつ使用するか、それがもたらすもの、およびそのトレードオフ。

2

あなたのクラスはhelperクラスです。このサフィックスを追加すると、このクラスを、他に配置するコードが含まれていないクラスとして扱う準備が整います。これは、汎用であるため、おそらくbelongの他のクラスにオブジェクト指向設計のゲーム。これは悪くない。ヘルパークラスは、多くの場合、拡張メソッドを備えた静的クラス(または一般に静的メソッドのみ)です。時にはそうではありません。 ヘルパーではないであるクラスは、もちろん、残っている唯一のクラスですprotagonists

いずれにせよ、あなたの質問に対する答えは、何度も何度も聞こえるかもしれない同じ答えです。場合によって異なります。あなたが達成しようとしていることは何ですか?新しいオブジェクトを作成する必要がある場合、メソッドを使用してオブジェクトの有効期間が終了すると、あなたはリソースを浪費していますになります。では、資源を無駄にしないための良い方法は何でしょうか?

  • メソッドを静的にします。完全に「非個人的な」メソッド呼び出しが1つだけ必要になるたびに、不要なインスタンス化を行う必要はありません。

そのささやきは何ですか?コンパイラの最適化についてのコメントはありますかTM

公平なポイントですが、オブジェクト指向プログラミングとは、手段人間にとって何か、コンパイラや技術については考えていませんのコードを書くことを意味します。あなたが気にしていたのが仕事への運転方法だけだった場合、毎日新しい車を注文しますか?おそらく静的メソッドを検討するでしょう(たとえば、所有していないバス、おそらく毎日同じ)。オブジェクト指向のコンテキストでは、そのメソッドの1つを使用するためだけにオブジェクトを作成します。ちなみに、オブジェクト自体から絶対に状態なし(つまりプライベートフィールド)を利用するだけですは意味をなしません絶対に何もないを提供します。はい、できます。オブジェクト指向プログラミングの場合、クラスはthe抽象化です。しかし、これは柔軟性を高めていません。あるファイルからコードを取得して別のファイルに配置するだけです。

多分それはあなたが欲しかったものです。あなたには反復的な方法があり、ファイルを小さくする必要があります。反復的なコードのように見える部分を取得し、それらを1つの場所に配置します。いいですねDRYは良い習慣です。Not-Repeating-Yourselfによって得られるボーナスポイントは、明快さ、保守性、移植性などと関係がありますが、何も得られません概念的な柔軟性。昔ながらのプログラミング(構造的、OOP以前)は、コード付きの数十(数百ではないにしても)の関数に基づいていました。関数はthe時代の抽象化単位です。しかし、人々はその関数に気づきました、抽象化ユニットとして、概念的な柔軟性をあまり提供しません。コード内のある時点でspecific関数を呼び出す必要があります。または、関数でdecideを呼び出す必要がありますそれはメソッドを呼び出すコードを持っているようなものではありません知らないことさえありますメソッドが何をするか、または実際のコードがどこに書かれるか(「複数の実装」のように、複数の場所に広がる可能性があるため)。

これは私に正確にをあなたの質問への答えにもたらします:クラスを意味あるものにしたいとき、あなたはフィールドの代わりにパラメータを使用します、つまりhold state。ステートレスクラスはインスタンスではなく、移植可能なコードリポジトリです。また、コンパイラとコンピュータは人工的にスマートであり、同じタイプのインスタンスのコードを複製しないため、これは実際には起こりません。ある店が無料の料理の本を配っていて、あなたが一人だとします。同じクックブックのコピーを2つ取得した場合、2つのクックブックがあり、ページ数が2倍になり、1コピーだけを購入した場合よりも2倍のストレージ領域が必要になります。料理したいだけでは意味がありません。これはリソースの浪費であり、メモリのオーバーヘッドの点で少しコストがかかりますが、コードのためだけにオブジェクトをインスタンス化しても意味がありません。 (保守目的で)コードを読む人は、インスタンスの背後に何が隠れているかを理解しようとし、何も特別なものを見つけることに戸惑います(驚きの原則を参照)。静的クラスの静的メソッドは、意図をより明確にします。

つまり、後で必要になる可能性があるために、参照を維持したいものがある場合、それはプライベートフィールドに格納するものです。それらに何らかの目的がある場合、それはそうです。たとえば、以前に作成された同じクエリをデータベースに作成する「リスク」があり、データベースがクエリ間で変更されていないこともわかっている場合、クラス内(マップ、たとえば)、すぐにそれを返します。クエリが新しい場合は、結果をキャッシュできます。これらの機能では、クラスの状態変数を保存する必要があり、その場合、「アンダーカバー」を提供できます。これらはほんの一例です。一般的な回答は引き続き有効です。状態(変更可能かどうかにかかわらず)を格納するクラスを作成する場合、この状態をプライベートフィールドに格納します。そして、状態を保存する必要があるかどうかは、まさにそれがあなたがモデル化していることと、それをどのようにモデル化するかによって異なります。

専門性を念頭に置いてオブジェクト指向プログラムを判断すると、明確さや読みやすさなど、オブジェクト指向設計が提供する最大の利点を見逃してしまいます。

1
Vector Zita