8

私はかなり長い間プログラミングをしてきましたが、オブジェクトを結合することになると、いつも壁に頭をぶつけているように見えるので、誰かが私が従うことができるリソースや黄金のルールを持っているかどうか疑問に思います。

特定の言語ではなく、小さな例を挙げましょう...

class Person {
    private int personnel_id
    private String first_name;
    private String last_name;
    private int personnel_level;
    //Lab labs[4]; <- Lab(s) the Person works in
}

class Lab {
    private int lab_id;
    private String lab_name;
    //Person[99] personnel; <- Person(s) working in the Lab
}

今のところctors/setters / getters / dtorsを無視して、いくつかのものをインスタンス化しましょう...

Person people = new Person[1500];
Lab labs = new Lab[10];

私の質問は..ここでのベストプラクティスは何ですか...

people["Gordon Freeman"].blewUp((Lab)"Black Mesa");
-> returns T/F

また...

labs["BlackMesa"].blownUpBy((Person)"Gordon Freeman");
-> returns T/F

または多分それは問題ではありません:S

私が取り組んでいる実際の例は、はるかに複雑です。何かをするときはいつでも、必要なPerson人全員にLab通知する必要があります。私はここで適用できる原則があるかどうかを理解しようとしています。

4

10 に答える 10

3

私の答えは、いくつかの既存の答えを組み合わせたものです。

ここで本質的な問題は、ここに隠された概念があるということです。このメソッドは実際にはラボ オブジェクトや人物オブジェクトについてではなく、それらの間の関係について話しているのです。(@dacris と @vs の提案による)

このような状況に対処する 1 つの方法は、二重ディスパッチのある言語を使用することです (@Ken さん、ありがとうございます)。

もう 1 つの方法は、自動生成されたコードを使用することです (@vs に感謝します)。この場合、どちらの方向にも使用できるメソッドがあります。

しかし、多くの場合、これらの解決策は実用的ではありません。言語全体を変更するのはやり過ぎに思えます。

ただし、自動生成されたソリューションから洞察が得られます。どちらの手法も合法である必要があります。したがって、両方の手法を手動で実装できます。

ただし、繰り返したくない場合は、このアプローチにより、どちらの方向も合法であることが明らかになります。だから、あまり汗をかかないでください。

Person オブジェクトに爆発以外の用途があるシステムをコーディングしている場合は、カップリングを Lab から Person に移動する (つまり、メソッドを Lab オブジェクトに配置する) 方がよいでしょう。 Lab オブジェクトまたは爆発関連のメソッドの変更に対処する必要があります。

... およびその逆。人が物を爆発させるだけなら、ラボを清潔で手付かずの状態に保つためのロジックがそこにあるはずです (これはラボにとって重要です!)

于 2010-07-15T10:20:23.380 に答える
2

Observer パターンと Publish/Subscribe パターンについて少し読みたいと思うかもしれません。あなたが説明しているのは、オブザーバー パターンの古典的なアプリケーションです。pub/sub パターンは、基本的に同じアイデアを、スケーリングを支援するためにもう少し抽象化したものです。

いずれにせよ、このパターンがすでによく知られていることを考えると、別の方法をとることで確実に利益が得られる状況に遭遇しない限り、その規則に従うことをお勧めします。

于 2010-07-15T04:06:37.870 に答える
1

英語を話しているように考えてください。一般的なルールは、動詞 (およびメソッド) は可能な限り「能動態」を持つべきであるということです。つまり、オブジェクトは何かを行うのではなく、何かを行うべきです。

イベントの場合は、受動態のほうがもう少し理にかなっています。ラボはそこにいる人を知る必要がありますが、ランダムな人 (同じラボで働いている人であっても) はおそらく知らないはずです。そのため、ラボが爆発したという通知ラボ自体から来るのが一番いいでしょう。しかし、実際には、その場合は個人 (またはチーム) の好みの問題です。

于 2010-07-15T03:36:06.673 に答える
1

あなたの例が何を意味するのか完全にはわかりませんが、

Craig Larman によるApplying UML and Patternsは、あなたが望むものを含んだ優れた本です。

この本は、責任の割り当てについて広く語っています。たとえば、Information Expert パターンを使用できます。この場合、関連する変数について最も多くの知識を持つオブジェクトに、メソッドを持つ責任が与えられます。

于 2010-07-15T04:39:00.180 に答える
1

あなたが正しい。これは、今日のほとんどのオブジェクト指向システムの主要な問題の 1 つだと思います。多くの場合、メソッドは自然にオブジェクトに「属している」ように見えますが、実際にはそうではありません。

複数のディスパッチを備えたシステムは、この問題をうまく回避します。たとえば、ディランでは、次のように言うことができます。

define method blows-up(p :: <person>, l :: <lab>) => explodes :: <boolean>;
  // ...returns #f or #t...
end method;

(c2.com の MultiMethods ページにリンクしました。これは、これを説明する上で最も悪い仕事をしていると思うからです。ウィキペディアには Multiple_Dispatch のページがありますが、その例はかなりひどいものです。)

于 2010-07-15T05:14:03.243 に答える
1

oO は、これについて別の視点を与えてくれます。実際、あなたは人物にも研究室にも興味がありませんが、それらの間の関係に興味があります。UML またはデータベースの観点から見ると、この関係が (メンタル) モデルの非常に新しい概念であることがわかります。上記の @dacris コメントも参照してください。彼は新しいクラスを紹介しています。

ORM (Object-Relational Mapping) を使用する場合、UML モデルを使用してエンジニアリングする場合のように、これらの 2 つのメソッドは自動的blowsUp()blownUpBy()コード生成され、それぞれの実行時チェックを使用して一貫性を確保します。

Larman の本には、このトピックに関する何かが含まれているはずです。

于 2010-07-15T06:01:28.730 に答える
0

一般的なグッド プラクティスではなく、現実世界とコーディング規約に関連していると思います。あなたの英語については、私はまだ people.notify(lab) を呼び出すことを好みます。ただし、誰が誰を呼び出したかについてのデータをラボに持たせたい場合は、lab.isNotifiedBy(people) を実行できます。

ここでの良い習慣は、あなたとあなたの同僚がコードを見て意味をなすことです。彼らはコードが何をするかを理解し、メソッドを見つけたい場合は、単に検索したり尋ねたりするのではなく、どこから始めるべきかを知っています。

于 2010-07-15T03:39:32.083 に答える
0

私は次のようなデザインが好きです。

let blackMesa = labs["BlackMesa"]
if (blackMesa.isDestroyed) 
{
    let destroyer = blackMesa.destroyer
}
于 2010-07-15T03:40:07.713 に答える
0

この場合、新しいオブジェクトを紹介したいと思います - LabExplosion

class LabExplosion
{
    private Person personResponsible;
    private Lab labAffected;
}

次に、LabExplosions のリポジトリをどこかに保持し、次のようにします。

// To find out if Gordon Freeman ever blew up Black Mesa
explosions.find("Gordon Freeman", "Black Mesa").length > 0;
// returns T/F
于 2010-07-15T04:27:18.613 に答える
0

ここでのベストプラクティスは何ですか...

ユースケースによって異なりますが、ユーザーはシステムをどのように使用しますか? によって「吹き飛ばされた」ラボでしょうPersonか?または、システムの使用例は、いくつかのPerson爆発を起こすことLabsですか?

または多分それは問題ではありません:S

最終的には同じ結果になりますが、ここで重要なのはコードの意味です。ラボが人々によって吹き飛ばされるのがばかげているように聞こえる場合は、それをしないでください。

したがって、BobTurbo が述べているように、黄金律は、システム内の「情報の専門家」( GRASPを参照) を見つけて、そのオブジェクトに制御を与えることです。

通常、システムがどのように使用されるかについて、ユーザー履歴または説明を定義します。たとえば、説明が次の場合です。

ある人物が何かを行った場合、ラボの全員に通知する必要があります。

そして、私にとっては、a が a でPerson動作し、Labそれが作成されると、その人は自分が取り組んでいるラボを受け取り、自分自身を登録して、その perticula ラボで何が起こっているかを通知されることを意味します。

ラボには通知する人のリストがあるため、ラボが通知を実行するのは理にかなっています (この場合、人はラボに制御を渡します)。

次に、おそらく次のPersonように定義できます。

labs.Person {
     - name: String
     - lab : Lab 

     + Person( withLab: Lab , andName: String ) {
           self.lab = withLab
           self.name = andName
           self.lab.subscribe( self ) // want to know what happens
      }


     + blowUpLab() {
           lab.boom!(blownBy:self)
       }
       // receive a lab even notification 
       // performed by "someone" 
     + labEvent( lab:Lab, by: Person  ) {
          // if is my lab and it wasn't me?
          if( self.labg .== lab .&& self .!= by ) {
             // ok it was someone else.... 
          }
       }
  }

したがって、人はラボで何かを行います。この場合、blowUpLabラボのメソッドを呼び出すことによってその人のラボを爆破するパブリック メソッドboom!です。

次に、Labメソッド アクションを実行し、最後にすべてのサブスクライバーに通知します。

labs.Lab {
    - labName:String
    - subscribers: Person[0..*]

    + subscribe( to: Person ) {
          subscribers.add( to ) 
      }

    + boom!( blowedBy: Person ) {
         // do blow up the lab 
         .... 
         // and then notify:
        subscriber.forEach( person: Person ) {
             person.labEvent( self, blowedBy )
         }
     }
 }

これがオブザーバーパターンです。

最後に、メイン アプリは人物とラボを作成し、ユース ケースを実行します。

 labs.MainApp {
     _ main() {
          blackMesaLab = Lab("BlackMesa")
          gordon = Person( withLab: blackMesaLab, andName: "Gordon Freeman")
          scott  = Person( withLab: blackMesaLab, andName: "Scott Tiger")
          james  = Person( withLab: Lab("SO Labs"), andName:" James Hetfield");

          persons = Array( gordon, scott, james )

          .... 

         while( true ) {
              // every now and then, have someone blowing up it's lab 
              if ( randomNumber() .== 42 ) {
                  person.at( randomPosition ).blowUpLab()
             } 
         }
       }
   } 

このメインアプリは、いくつかのラボを含む 3 人の人物を作成します。そのうちの 2 人だけが関連しています (スコットとゴードン)。

blowUpLabそのうちの 1 つがランダムにメッセージを受け取り、メソッドを実行します。ラボは、そのラボのすべてのサブスクライバーに通知します。

だから、ジェームズ・ヘットフィールドがその研究室を吹き飛ばしても、誰にも通知されません:)

ポイントは、ユースケースを説明し、そこにいる情報専門家を特定することです。そのオブジェクトにコントロールを与え、そのオブジェクトがコントロールを他のオブジェクトに依存させますが、ユースケースに応じてのみ

それが理にかなっていることを願っています。

于 2010-07-15T05:51:33.543 に答える