1

アラン・ケイからの次の引用に出くわしたとき、私は以前に記事を読んでいました:

「多くのいわゆるオブジェクト指向言語にはセッターがあり、オブジェクトにセッターがある場合は、それをデータ構造に戻します。」

この記事は、これがベストプラクティスではなく、長期的に開発するアプリケーションに損害を与える可能性があることを示唆しています。

私はC、Java、PHP、Rubyなどの経験を持つCompSciの学生です。したがって、概念と実践としてのOOPにかなり精通していますが、決して専門家ではありません。

私の質問はこれに要約されると思います:

OOプログラムを作成するとき、(ゲッターを使用して)フィールド値にアクセスし、setterメソッドを使用してそのオブジェクトのフィールドを単純に調整するのではなく、変更された値に基づいて新しいオブジェクトを作成することは、意味的に正しいですか(そしてベストプラクティスの問題です)。

または、木片があり、その元の部分から木を切り取った場合、それをより少ない質量の同じ部分としてモデル化するか、完全に新しい部分としてモデル化する必要があります。

セッターの使用はより簡潔であるように思われ、非常に多くのオブジェクトを作成する場合はガベージコレクションが問題になるため、実用的ではなく理論的な観点からこの質問に取り組んでいます。

よろしくお願いします!

4

7 に答える 7

2

An object must have at least one of two types of responsibilities: behaviour and knowledge. Behaviour defines how the object reacts to events within its execution context, and knowledge defines what the object knows.

Behaviour is implemented as methods where the method names map onto the events that trigger reactions. Knowledge is implemented as getters that return values mapping to the knoweldge being queried.

このように設計および実装されたオブジェクトは、外部イベントに反応してのみオブジェクトの状態が変化するため、セッターが必要になることはめったにありません。そうは言っても、外部イベントをセッターとして実装することもできますが(たとえば、car.setSpeed(...))、通常はより適切な名前を探す必要があります(たとえば、car.accelerateTo(...)およびcar.decelerateTo(。 ..))。

于 2012-04-30T13:05:28.503 に答える
1

それは設計の問題です。OOの基本原則はカプセル化です。Circleオブジェクトがあるとします。半径用のセッターと周囲用のセッターを使用できます。ただし、もちろん、両方がリンクされているため、周囲長を設定すると半径も変更され、半径を設定すると周囲長も変更されます。そうでない場合は、実際にはオブジェクトはもうありませんが、カプセル化されていない単純なデータ構造です。

現在、一部のオブジェクトは変更可能であり、他の一部は変更可能ではありません。たとえば、文字列または整数は不変です。値が設定されると、その値は変更できません。文字列を別の文字列に連結すると、2つの元の文字列に影響を与えることなく、新しい文字列インスタンスが作成されます。不変オブジェクトは状態が1つしかないため、理解と使用が簡単です。また、本質的にスレッドセーフです。ただし、パフォーマンスの問題が発生する可能性があります。たとえば、ループ内で連結すると、メモリを消費する一時的なStringインスタンスが大量に作成され、GCする必要があります。これがStringBuilderが存在する理由です。基本的には可変の文字列です。

To conclude: there is no definitive answer, because it all depends on the kind of object, and the way it's used. In general, favor immutable objects over mutable ones. Favor less mutable objects over more mutable ones.

于 2012-04-30T12:44:45.750 に答える
0

あなたは2つの質問をしています:

1)オブジェクトにパブリックフィールドを含めても大丈夫ですか?

少なくとも1つの理由で、メソッドを介してオブジェクトのフィールドにアクセスする場合は、通常、メンテナンス/デバッグの観点から優れています。メソッドは、フィールドに変更するための共通エントリを導入し、カスタムロジックを追加して、無効な変更を防止したり、不変条件を更新したりできます。要求された変更とその状態を一致させるためのオブジェクトの。オブジェクトに内部状態がない場合は、メソッドは必要ありません(ただし、それでもお勧めします。デバッグ用のすべてのアクセスに単一のブレークポイント領域が導入されます)。

2)可変オブジェクトまたは不変オブジェクトを使用する必要がありますか?

どちらのアプローチも正しいです。不変オブジェクトを使用すると、既存のオブジェクトの状態を変更できないため、コードを簡単に推論できます。OTOHは、より多くのオブジェクトで終わる可能性があるため、より多くのメモリを使用するか、ガベージコレクターがより多くの作業を行うことになります。可変オブジェクトは反対の長所/短所を提供します

于 2012-04-30T12:41:58.337 に答える
0

私の意見では、問題のオブジェクトを「不変」としてモデル化するかどうかによって異なります。モデルによってはこれが完全に理にかなっている場合があります。この場合、セッターメソッドのコーディングは控えてください。

一般的に言って、セッターを使わない理由はありません。さらに、セッターメソッドを定義するための特殊な構文を提供する多くの言語(C#、AS3)を見つけることができます。

于 2012-04-30T12:42:09.317 に答える
0

これは完全にあなたが達成したいことに依存します。インスタンスのプロパティを変更する場合は、setterまたは同様のメソッド(carveOutSomeWood())を使用する必要があります。以前のバージョンにアクセスする必要があり、新しいインスタンスを生成する必要がある場合は、ある種のcreateCopy()/clone()メソッドを実装してコピーを作成し、carveOutSomeWood()その新しいインスタンスに適用できます。

古いインスタンスのプロパティを読み取り、自分で作成して新しいインスタンスを作成することはお勧めしません。主な理由(他にもあるかもしれません)は、クラスが変わるかもしれないということです。次に、クラスの外部で行われるため、新しいインスタンスの作成も変更する必要があります。単にcreateCopy()メソッドを使用する場合、その変更を説明するのはクラスの責任になります。

derive()内部でコピーを作成し、いくつかの変更を適用するメソッドを直接導入することもできます。

于 2012-04-30T12:43:44.853 に答える
0

セッターは内部実装を公開し、いくつかの問題を引き起こす可能性があります。オブジェクトを設定し、新しい割り当て状態に基づいていくつかのアクションを実行する場合、割り当てられたオブジェクトが外部で変更されると問題が発生する可能性があります。

于 2012-04-30T12:44:02.417 に答える
0

ある変数fooが、あるフィールドを持つクラスオブジェクトを識別しbar、現在はfoo.bar=5;foo.bar1つは6に等しいことを望みます。あなたの質問はfoo、同じオブジェクトを識別し続けても、そのオブジェクトbarを6に変更する方がよいのか、それとも、フィールドが6になることfooを除いて、識別に使用したものと同じ新しいオブジェクトを識別する方がよいのかということです。 bar両方のアプローチが正しい場合、フィールドの変更(直接またはsetFoo()呼び出しによる)は、新しいオブジェクトを作成するよりも効率的である傾向があり、したがって「より良い」でしょう。ただし、多くの場合、正しいアプローチは1つだけです。もう1つは単に「それほど良くない」ということではありません

どのアプローチを使用するかを決定する際の50,000ドルの質問は、カプセル化されることになっているものfooと、それによって識別されるオブジェクトです。

  • 共有オブジェクトfooへの参照を保持し、それへの他の参照がそれを使用して「bar = 5」の状態をカプセル化する場合、barの変更は間違っています。唯一の正しいアプローチは、新しいオブジェクトを作成し、元のオブジェクトではなくそれを識別するように変更することです。foo

  • 特定のオブジェクトを識別するユニバース内の任意の場所で唯一の参照を保持する場合foo、新しいオブジェクトの作成または既存のオブジェクトの変更は意味的に同等ですが、前述のように、既存のオブジェクトの変更はより高速になる傾向があります。

  • 他の参照が存在するオブジェクトfooを識別し、その目的が他の参照によって識別されるオブジェクトを識別することである場合(これらの他の参照との接続を効果的に形成する)、foo別のオブジェクトを識別するように変更すると、そのオブジェクトは、代わりに新しいオブジェクトを識別するために更新されます。

  • フィールドbarfinal、またはその他の方法で変更から保護されている場合、特定のオブジェクトへの唯一の参照を保持している場合でも、新しいオブジェクトを作成してそれをfoo識別する以外に方法はありません。

2番目のケースと4番目のケースがおそらく最も一般的です。これらは、「不必要に新しいオブジェクトを作成しない」という原則によって処理できます[ケース2では、新しいオブジェクトの作成を回避できます。ケース4ではできません]。その原則は、ケース3も簡単に処理できます[必要なことを実行するように促すため]。そのルールの観点からの唯一の問題のあるケースは最初のものです。その場合でも、参照が共有されているがIDをカプセル化することを目的としていない場合は、新しいオブジェクトの作成が必要になることを認識することが重要です。

不変オブジェクトの人気の背後にある本当の理由の1つは、可変オブジェクトを適切に使用するには、どの参照がIDをカプセル化する必要があり、どの参照がカプセル化しないかを知る必要があることだと思います。不変のクラスを使用すると、そのような問題を回避できます。

于 2013-12-06T19:18:04.073 に答える