none
form2 からform1をクローズするには RRS feed

  • 質問

  • 全くの初心者です。どなたか教えてください。

    form1 から別の form2のインスタンスmyFormを作成し2つフォームを表示(myForm.show)しています。form2でMe.Close を実行したときにform1 もクローズしたいのですが方法がわかりません。

    (つまりいくつかフォームがあって 特定のフォームの終了処理で他のフォームも閉じたいのです。スタートアップに指定したフォームは除いて)

    form1 自信も他のフォームからインスタンスで作成・表示されているのですが・・・・

    (form1の呼び出し元のフォームはすでにクローズされています。)

    初歩的な質問で申し訳ありませんがよろしくお願いします。

    2008年11月19日 12:35

回答

  • form2でMe.Closeしてform2を閉じていますよね。このMeというのはform2のインスタンスです。同じようにform1のインスタンスが手に入れば、そのCloseメソッドを呼んでやればよいわけです。では、form2でform1のインスタンスを手に入れるにはどうすれば良いでしょうか?

    いろいろな方法が考えられますが、基本はform1でform2をShowする際に、form1のインスタンスをform2に渡してあげることです。手っ取り早いのはform2をnewする際に渡してしまうことです。つまり、コンストラクタの引数で渡してしまいます。

    ポイントは閉じたいフォームのインスタンスを如何に手に入れるかです。これがわかれば後は工夫です。

    2008年11月19日 12:50
    モデレータ
  •  しげちゃん さんからの引用
    (つまりいくつかフォームがあって 特定のフォームの終了処理で他のフォームも閉じたいのです。スタートアップに指定したフォームは除いて)

     

    通常こういった場合は OwnerForm を使うかするのが正しいです。
    親子関係にない Form でこういった実装は直感的ではありません。
    親子関係でない Form の参照を (閉じるためだけに) 保持しているのは行儀が良いものではないと考えます。

     

    Form1 がスタートアップ フォームだった場合ですが、(ああ、今回は違うみたいですね)
    Form2 で Form1 を閉じようとすること自体が変ですし、うまく動作しないこともあります。


    私は呼び出し元である Form1 で Form2 の Close を関知できるようにすべきだと思います。
    つまり、AddHandler form2.FormClosed, AddressOf form2_FormClosed を form2.Show メソッドの前に記述し、
    Form1 に form2_FormClosed(ByVal sender As Object...) プロシージャを作成してここで Me.Close を実行します。

     

    VB2005

    ' Form2 を開くメソッドと仮定
    Public Sub
    MosaMosaAA()
        Dim form2 As New Form2()
        AddHandler form2.FormClosed, AddressOf form2_FormClosed
        form2.Show()
    End Sub

    ' Form2 の FormClosed イベントをここで関知
    Private Sub form2_FormClosed(ByVal sender As Object, ByVal e As FormClosedEventArgs)
        Me.Close()
    End Sub

     

    これで Form2 が閉じられた時、呼び出し元である Form1 も '自発的に' 閉じます。
    2008年11月20日 3:50

すべての返信

  • form2でMe.Closeしてform2を閉じていますよね。このMeというのはform2のインスタンスです。同じようにform1のインスタンスが手に入れば、そのCloseメソッドを呼んでやればよいわけです。では、form2でform1のインスタンスを手に入れるにはどうすれば良いでしょうか?

    いろいろな方法が考えられますが、基本はform1でform2をShowする際に、form1のインスタンスをform2に渡してあげることです。手っ取り早いのはform2をnewする際に渡してしまうことです。つまり、コンストラクタの引数で渡してしまいます。

    ポイントは閉じたいフォームのインスタンスを如何に手に入れるかです。これがわかれば後は工夫です。

    2008年11月19日 12:50
    モデレータ
  •  しげちゃん さんからの引用
    (つまりいくつかフォームがあって 特定のフォームの終了処理で他のフォームも閉じたいのです。スタートアップに指定したフォームは除いて)

     

    通常こういった場合は OwnerForm を使うかするのが正しいです。
    親子関係にない Form でこういった実装は直感的ではありません。
    親子関係でない Form の参照を (閉じるためだけに) 保持しているのは行儀が良いものではないと考えます。

     

    Form1 がスタートアップ フォームだった場合ですが、(ああ、今回は違うみたいですね)
    Form2 で Form1 を閉じようとすること自体が変ですし、うまく動作しないこともあります。


    私は呼び出し元である Form1 で Form2 の Close を関知できるようにすべきだと思います。
    つまり、AddHandler form2.FormClosed, AddressOf form2_FormClosed を form2.Show メソッドの前に記述し、
    Form1 に form2_FormClosed(ByVal sender As Object...) プロシージャを作成してここで Me.Close を実行します。

     

    VB2005

    ' Form2 を開くメソッドと仮定
    Public Sub
    MosaMosaAA()
        Dim form2 As New Form2()
        AddHandler form2.FormClosed, AddressOf form2_FormClosed
        form2.Show()
    End Sub

    ' Form2 の FormClosed イベントをここで関知
    Private Sub form2_FormClosed(ByVal sender As Object, ByVal e As FormClosedEventArgs)
        Me.Close()
    End Sub

     

    これで Form2 が閉じられた時、呼び出し元である Form1 も '自発的に' 閉じます。
    2008年11月20日 3:50
  • じゃんぬねっとさん ありがとうございました。

    おかげで無事解決しました。確かに考え方はその通りだと思うし私もそうするしかないと納得もしていたのですが,じゃあ具体的には何を使ってどうするのかという知恵が初心者故(理由にはならないか・・・・)見えてこないのです。一つ一つ経験を積まないといけないのでしょうね・・・きっと・・・

    また一つ勉強ができました。

    これに懲りずまたご指導ください。

     

    2008年11月20日 10:41
  • 解決したようで何よりです。

     

     しげちゃん さんからの引用
    確かに考え方はその通りだと思うし私もそうするしかないと納得もしていたのですが,じゃあ具体的には何を使ってどうするのかという知恵が初心者故(理由にはならないか・・・・)見えてこないのです。一つ一つ経験を積まないといけないのでしょうね・・・きっと・・・また一つ勉強ができました。これに懲りずまたご指導ください。

     

    すみません。 きつい口調だったでしょうか?
    もしそうだとすれば、申し訳ないと思います。(もちろんそういうつもりがあったわけではないです)

     

    考え方の道筋はできていたということで素晴らしいと思います。 今後もし質問することがある場合は、それを文章に起こして頂けると回答者はうまく回答をつけやすい、あるいはもっと良い案が提案できると思います。 今後とも頑張ってくださいませ。

    2008年11月20日 10:49
  • trapemiya さん ありがとうございます。

    考え方は当たり前にわかるのですが,具体的な方法がわからないのです。以前のVB であれば直接的にコードを書けばすんだのですが .NETになってからはそう簡単にはいかないようです。ひとつひとつ手順(これがなかなか数が多くてわからない)を踏まないとだめなんですね。

    しかし じゃんぬねっと さんからいただいたアドバイスで何とか解決できました。

    今後もご指導ください。

     

     

     

    2008年11月20日 10:50
  •  しげちゃん さんからの引用

    考え方は当たり前にわかるのですが,具体的な方法がわからないのです。

     

    form1とform2がどれぐらい協調して動くのかわからなかったのですが、じゃんぬさんのイベントを用いる方法がベストな解だったようですね。しかし、これで終わりにせず、ぜひインスタンスというものをよく理解するようにがんばってみて下さい。なぜなら、オブジェクト指向の世界ではインスタンスが協力し合って動いているからです。他のケースでform1とform2をもっと密接にしたくなった時、例えばform2からform1のプロパティやメソッドを呼びたくなった時、きっと役に立ちます。どうプログラミングしてよいかわからないというのは、このインスタンスが協力しあって動いている世界を想像できないからじゃないかと思います。これが想像できるようになれば、初心者から大きく一歩踏み出したことになるでしょう。

    2008年11月20日 15:50
    モデレータ
  •  trapemiya さんからの引用
    例えばform2からform1のプロパティやメソッドを呼びたくなった時

     

    これは Windows アプリケーションではお目にかかりたくないコードだと思います。


    兄弟のような関係のフォームが仕様上あった場合、やむなく相互で値の渡し合いをしているようなコードを見かけることがありますが、これもイベントや DataBinding などを使えば回避できます。 今回は呼び出し元と呼び出し先の関係が明らかだったので、あまり関係がないお話ではありますが...

    このインスタンスが協力しあって動いている世界を想像できないからじゃないかと思います。これが想像できるようになれば、初心者から大きく一歩踏み出したことになるでしょう。

     

    私はいつも一方からの支配にしています。 呼び出されているという関係がある時点で呼び出された側は呼び出し側を意図したくないです (客先都合で画面遷移仕様が変わるような時、手直しが 2 クラスに及ばないので楽です)。 だから今回迷わず最も良いと思われる方法を提示できたつもりでいました。 確かに私は初心者から先に踏み出せていないかもしれませんw

    2008年11月21日 12:21
  •  じゃんぬねっと さんからの引用

    これは Windows アプリケーションではお目にかかりたくないコードだと思います。


    兄弟のような関係のフォームが仕様上あった場合、やむなく相互で値の渡し合いをしているようなコードを見かけることがありますが、これもイベントや DataBinding などを使えば回避できます。

     

    お目にかかりたくないコードだと考えられる理由は何でしょうか? 何か前提があると思うのですが、それとも、どのような場合でもフォーム同士はイベントで結びつく必要があると考えられているのでしょうか?前提があるとすれば、親子関係という前提でしょうか? だとすれば、何をもって親子関係を定義されているのでしょうか?

     

    質問ばかりでは何ですので、少し私の考えを述べます。しかし、誤解の無いように説明しきれるかどうか難しいと思っています。そう単純なものではないからです。

     

    まずイベントですが、私はインスタンスを渡してそのメソッドを呼ぶのと本質的に同じであると考えています。form1がform2のインスタンスを生成したとしましょう。イベントとはイベントハンドラをform2に渡し、form2でイベントハンドラを実行しているということです。同じようにform2にform1のインスタンスを渡し、form2でそのインスタンスのメソッドを実行します。どちらもform2でform1のメソッドを実行している点で同じです。

     

    では両者の違いは何でしょうか? 言うまでもありませんが、イベントはデリゲートを利用することによって疎に結びついています。form2へform1のインスタンスを渡す場合は、form2という型に限定しているという点で密な関係になってしまいます。つまり、イベントとは疎の結合、およびインスタンスをイベントがあるクラスへ渡す必要がないという大変便利な機構です。

     

    一方で、form2へform1のインスタンスを渡す場合でも、インターフェースを介すことにより、疎の結合にすることができます。しかし、インスタンスを渡す必要がある点はイベントより手間のかかる部分です。当然、インターフェースも用意しなければなりません。イベントに比べると面倒です。

    コールバックして欲しい要件は昔からよくあることです。なのにいちいちインターフェースを定義して、インスタンスを渡すなんてことやっていたら面倒です。なので、コールバックという限定的な使い方のためにイベントが用意されているんだと思います。私から見れば一種の便利機能です。

     

    そういうわけでイベントが便利に使える場合にはどんどん使えば良いと思いますし、だからといってイベントしか使ってはいけないということはないと思います。例えば画面が遷移していくような場合など、form2が主導的立場になるのであれば、form1のプロパティを呼んだり、メソッドを呼んだりした方がロジックが組みやすい場合もあるでしょう。もっともこの段階でじゃんぬさんの言われている親子関係がたぶん崩れているんでしょうが。

     

    う~ん、なかなかまとめるのがやっぱり難しいですね。

    2008年11月21日 15:06
    モデレータ
  •  trapemiya さんからの引用

    どちらもform2でform1のメソッドを実行している点で同じです。

     

    イベントの場合は言ってみれば実行時解決のポインタが呼び出されるので結果論ではないですか?

    そういう意味ではform2はform1に依存していませんよね。

    form2 クラスとしてはだれがイベントを拾おうとしているのかさえ知りませんし。

     

    trapemiyaさんもオブジェクト指向という言葉を出していますが

    設計論の観点では、依存関係の一方通行化はまず守るべきではと思っています。

     

    実際インスタンスを渡すような場面が無いわけではないのですが

    先のポリシーから、それもありだが第一選択肢ではないよ、というのが

    じゃんぬさんの考えでしょうし、私の考えです。

     

    逆にお聞きしますが、

    先の考えからからいくと、

    form2が閉じたらform1が閉じるというのは、form1の仕様であり、そこにform2はからまない

    ということになるのですが

    たとえば、form1が閉じたらform2も閉じるという仕様がさらにあったら

    お互いにインスタンスを渡しあうのでしょうか?

    それとも今回の場合に限り「これでいいよ」というだけなのでしょうか?

    2008年11月21日 18:00
  •  まどか さんからの引用

     
    イベントの場合は言ってみれば実行時解決のポインタが呼び出されるので結果論ではないですか?

    そういう意味ではform2はform1に依存していませんよね。
    form2 クラスとしてはだれがイベントを拾おうとしているのかさえ知りませんし。


    イベントに関しては私は疎な結合と言っていますので、まどかさん同様、依存していないと考えています。同様にインスタンスメソッドもインターフェースを介せば疎の結合になります。イベントと同様にポインタを呼び出します(この表現は正確ではありませんが)。form2はだれのインスタンスメソッドを実行するかさえ知りません。

     

     まどか さんからの引用

    設計論の観点では、依存関係の一方通行化はまず守るべきではと思っています。

     

    実際インスタンスを渡すような場面が無いわけではないのですが

    先のポリシーから、それもありだが第一選択肢ではないよ、というのが

    じゃんぬさんの考えでしょうし、私の考えです。


    稚拙な文章のためうまく伝わっていない力不足を感じますが、私もそう思ってます。
    じゃんぬさんは
    「これは Windows アプリケーションではお目にかかりたくないコードだと思います。」
    と言われてます。私はここが引っかかったのです。まどかさんも、「実際インスタンスを渡すような場面が無いわけではないのですが」と言われていますので、たぶん、根底は私と同じではないかと思います。

     

     まどか さんからの引用

    逆にお聞きしますが、

    先の考えからからいくと、

    form2が閉じたらform1が閉じるというのは、form1の仕様であり、そこにform2はからまない

    ということになるのですが

    たとえば、form1が閉じたらform2も閉じるという仕様がさらにあったら

    お互いにインスタンスを渡しあうのでしょうか?

    それとも今回の場合に限り「これでいいよ」というだけなのでしょうか?


    これも先に述べていますが、イベントが利用できる場合は積極的に使えば良いと書きました。じゃんぬさんの回答が今回はベストな方法であったのでしょうとも書いています。くどいかもしれませんが、「これは Windows アプリケーションではお目にかかりたくないコードだと思います。」に引っかかっただけです。どのような場合でもイベントやバインディングで処理しなければならないとは思わない、というのが私の考えです。form1とform2の関係によって設計が変わるべきだと思います。それで、じゃんぬさんには、この前提となっているのは親子関係がある場合ですか?と質問しています。

     

    私の反省点としては、しげちゃん(さん)が全くの初心者と言われていること、そして、Me.Closeでform2をクローズしているが、同様にform1をクローズしたいというところから、インスタンスと言うものを全く、もしくはほとんど理解されていないと思い、そちらを理解してもらいたいという思いが強い回答になってしまったことです。インスタンスを理解することが、オブジェクト指向の最も基本であることの一つであると考えているからです。
    そうやって反省していますので、じゃんぬさんのイベントを使った回答はナイスなフォローだったと思って感謝していますし、ベストなソリューションだと思います。

     

    まどかさんにしてもじゃんぬさんにしても、こうやって反応していただけるのは大変ありがたく思います。こういうことで他の方の意見が聞けたり、オブジェクトというものをもう一度再考するきっかけになるのですから。なので、どんどん突っ込んでください。自分ももっと勉強したいと思っておりますので。

    2008年11月22日 2:26
    モデレータ
  • 貴重なアドバイスありがとうございます。インスタンスについての考え方が少しではありますがわかりかけてきたように思います。書籍によればいとも簡単にかいてありますよね。概念は理解できるのですが、どのようなものがどこまで・・・・これがなかなか把握しきれないというのが現実です。何でもまるでコピーするかのようにできてしまうことが不思議にさえ思えるのです。限界は・・・?なんて悩んでしまったりです。

    ご助言の通り、古着を脱ぎ捨てて挑戦したいと思います。

     

    しかし、私の質問からいろいろ盛り上がっていますね。なにか宇宙語に近いところもあるのですが何となく考え方はわかるような気がします。

    2008年11月22日 4:30
  •  trapemiya さんからの引用
    お目にかかりたくないコードだと考えられる理由は何でしょうか?

     

    これは、trapemiya さんが書いている "イベントはデリゲートを利用することによって疎に結びついています。" の部分に当たるのかなと思います。 その後の文章についても細かい点を除けばほぼ同意見かなと思われますので省略できるところは省略します。

     

    何か前提があると思うのですが、それとも、どのような場合でもフォーム同士はイベントで結びつく必要があると考えられているのでしょうか?

     

    (大人の事情を抜きにして、仕様上) できるなら、それが望ましい場合がほとんどであると考えています。 その理由も trapemiya さんが書かれている通りなので何がひっかかっているのかちょっとわからなかったのですが、"どのような場合でも" という表現が付け加えられているので、どこで分別しているのかについて問われているのかなと思いました。

     

    "どのような場合でも" という意図があって発言したわけではないですが、"お目にかかりたくない" 点では "どのような場合でも" は確かに当てはまると思います。 もっと踏み込んで言うのであれば、「進んで実装すべきでない | したくない」 という意味も含めて良いと思います。 「仕様変更で回避してしまいたい」 という表現でも良いでしょう。

     

    "どのような場合でも" とあるので一応、突っ込まれないように説明を加えておきます (どうでもいいところなのでグレーの文字色にしました。読み飛ばしても問題ないです)。 たとえば MDI Form には Child と Parent の関係があります。 Owner Form も主従関係があります。 これらはそうしなければならないので "どのような場合でも" には当てはまらないです。 誤解してはいけないのは、これらは親子関係を明示する必要があってそうしているだけであり、情報を取得するためのものではないということです。 最近どこかの掲示板でも述べたように、Owner から (オーナーフォームの) 情報を取得しているコードを見かけることがありますが、これは書き直したくなるくらいイヤなコードです。 これなら trapemiya さんが方法を示したように Form の厳密な型を定義して渡してもらう方がまだマシという厳しいことも書いたと記憶しています。 

     

    前提があるとすれば、親子関係という前提でしょうか? だとすれば、何をもって親子関係を定義されているのでしょうか?

     

    最初に断っておきますが、私は "親子関係" という言葉は使っておりません。 いや、厳密には "親子関係" という言葉を使っていますが、この話の流れとは関係のない部分で使っています。 "親子関係" という言葉を使った発言で述べたかったのは 「ある FormA とある FormB を同じタイミングで閉じたい場合は Owner を使って親子関係のようにして、呼び出し元が閉じられたから呼び出し先も閉じるという流れが望ましく、今回のように呼び出された側が閉じたから呼び出し元も閉じるはあまり直感的ではない」 という説明をするためです。 ちなみに "兄弟" という表現についてですが、これは Form1 と Form2 が別の Form0 から呼び出され階層上同じような位置関係にある場合を指しています (これは VSUG かどこかでそういう表現を使っていたので使ってしまいましたが、My 用語チックですので控えた方が良いかもしれませんね。 My 擁護は控えなくても良いと思いますがw)。

     

    私以外の方にはどうでも良い 「断り」 が長くなってしまいましたが、ともかく trapemiya さんの話の流れでは "親子関係" という言葉は使っていないのですよね。 誤解を招きやすいので、「呼び出し元」 「呼び出し先」 というような表現を使っているハズです。 ですので "何をもって" と言われても話の前提が間違っているのでこの点については何を意図しているのか良くわからないです。 申し訳ありません。

     

    ただし、どんな前提があるかについては答えてみようと思います。 いろいろパターンがあるので、今回発言した範囲だけで答えますと、今回のように呼び出し元と呼び出し先という関係が明らかな場合を前提とさせて頂いても問題ないかなと思います。 というよりそういうつもりで書きました。 FormA が FormB を呼び出している時点で FormA は FormB を感知するのは致し方ありません。 しかし FormB から FormA を感知するとモジュール同士が依存してしまいます。 "私はいつも一方からの支配にしています。" というのは、呼び出し元と呼び出し先の関係が明らかな場合です。 でなければ支配できないですからね。 これ以降の説明は trapemiya さんご自身もなさっているので省略しても良さそうですね。

     

    そういうわけでイベントが便利に使える場合にはどんどん使えば良いと思いますし、だからといってイベントしか使ってはいけないということはないと思います。例えば画面が遷移していくような場合など、form2が主導的立場になるのであれば、form1のプロパティを呼んだり、メソッドを呼んだりした方がロジックが組みやすい場合もあるでしょう。もっともこの段階でじゃんぬさんの言われている親子関係がたぶん崩れているんでしょうが。

     

    くどくて申し訳ないですが、"親子関係" という表現は (その話題では) していないです。 が、仰りたい内容については概ね理解でき、そのとおりかなと思います。 もし Form2 が Form1 から呼び出されているのに Form2 が主導的立場になるのであれば (親子関係ではないですが) 概念上の然るべき関係は崩れており、仕様変更をしたくなる部分にあたると思います。

     

    trapemiya さんの今回の発言ですが、自分自身の疑問に自分自身が華麗に答えているようにしか見えないので、何が疑問点かが実はよくわかっていないです。 あるとすれば "親子関係" と "どんな場合でも" とあるので (そういう意図があって途中の発言を書いたつもりはなかったのですが)、ここの分別と定義を問われているのかなと思い、自分の答えられる範囲で答えさせて頂きました。 しかしやはり大筋を言えば trapemiya さんが最初からわかっていたというような説明を自分自身でしているので、私がいろいろ書くまでもないような気がしました。 "確認" ということなんでしょうか? よくわかっていないです。

    2008年11月22日 12:39
  • まどかさん、フォローありがとうございます。 いつも助かっております。

     

     trapemiya さんからの引用
    イベントに関しては私は疎な結合と言っていますので、まどかさん同様、依存していないと考えています。同様にインスタンスメソッドもインターフェースを介せば疎の結合になります。イベントと同様にポインタを呼び出します(この表現は正確ではありませんが)。form2はだれのインスタンスメソッドを実行するかさえ知りません。

     

    ん? "インターフェイスを介せば" の話はどこから飛んできたのでしょうか? 「言語仕様上のインターフェイス」 ではなく 「広義のインターフェイス」 のことでしょうか? だとすれば、引数にしても、保持しておく変数にしても  Form1 と互換のある 「型」 を持たなければならないという点で 「依存度」 が違うと思います。 厳密でない型であったとしても (そんな選択をする人はなかなかいないと思いますが) 概念上依存していることになります。 まどかさんの言いたいことはまさにここで、"依存関係の一方通行化" という表現がまさにここに当たると思います。 これを守ることで私は修正が両方に及ぶのを防ぐことができますという説明をしています。 「モジュールの結合度」 だけで分別してはいけないということですね。

     

    「これは Windows アプリケーションではお目にかかりたくないコードだと思います。」と言われてます。私はここが引っかかったのです。まどかさんも、「実際インスタンスを渡すような場面が無いわけではないのですが」と言われていますので、たぶん、根底は私と同じではないかと思います。

     

    うーん、まどかさんの言う "実際インスタンスを渡すような場面が無いわけではないのですが" というのは、私が主張している 「呼び出し先である Form2 が呼び出し元である Form1 に感知するのはおかしい」 とはまた違う話ですよね。 で、私が主張しているこの部分については、"依存関係の一方通行化" で私に賛同なさっていると思います。 まどかさんが述べられている "実際インスタンスを渡すような場面が無いわけではないのですが" というのは、「trapemiya さんが書いた 'その部分に関しては' 確かにそうですが、第一選択肢ではない といった前置きなのだと思います。

     

    これも先に述べていますが、イベントが利用できる場合は積極的に使えば良いと書きました。じゃんぬさんの回答が今回はベストな方法であったのでしょうとも書いています。くどいかもしれませんが、「これは Windows アプリケーションではお目にかかりたくないコードだと思います。」に引っかかっただけです。

     

    説明済みの部分については省略します。

     

    どのような場合でもイベントやバインディングで処理しなければならないとは思わない、というのが私の考えです。form1とform2の関係によって設計が変わるべきだと思います。それで、じゃんぬさんには、この前提となっているのは親子関係がある場合ですか?と質問しています。

     

    その部分に関しては、"兄弟のような関係のフォームが仕様上あった場合、やむなく相互で値の渡し合いをしているようなコードを見かけることがありますが" とバッチリ前提を書いています。 なぜ勝手に "どのような場合でも" という解釈をされてしまっているのでしょうか?

     

    私が上記のような前提で 「イベント」 と 「DataBinding」 について書いたのはなぜかがわかっていらっしゃらないようですが、これは trapemiya さんが、

     

    他のケースでform1とform2をもっと密接にしたくなった時、例えばform2からform1のプロパティやメソッドを呼びたくなった時、きっと役に立ちます。どうプログラミングしてよいかわからないというのは、このインスタンスが協力しあって動いている世界を想像できないからじゃないかと思います。これが想像できるようになれば、初心者から大きく一歩踏み出したことになるでしょう。

     

    と書いていたからです。 このスレッドの流れからして Form2 は Form1 から呼び出される Form と考えるのがフツーです (何も書いていないのですから、フツーはそう捉えるでしょう)。 で、"その呼び出されちゃった Form2 から呼び出し元の Form1 のプロパティやメソッドを呼び出したくなった時" なんてのは私にはありませんし、そんなコードは書きたくありませんぜ。 という意味で書きました。

     

    ですので "初心者から一歩踏み出した" という結論には私は反対です。 もちろん 「この表現は上から目線だ」 なんて意味ではなく、賛成できないという意味です。 しかし真っ向から反論するのはフレームの元なので、わざと自虐的な表現にして柔らかく言ったのでした。 (おいおい、お前 (じゃんぬ) が気を使って発言しているのかと思われそうですがw これは本当の話ですw)

     

    私の反省点としては、しげちゃん(さん)が全くの初心者と言われていること、そして、Me.Closeでform2をクローズしているが、同様にform1をクローズしたいというところから、インスタンスと言うものを全く、もしくはほとんど理解されていないと思い、そちらを理解してもらいたいという思いが強い回答になってしまったことです。インスタンスを理解することが、オブジェクト指向の最も基本であることの一つであると考えているからです。

     

    ここも本題とは関係のない突っ込みになるので文字色はグレーにします。 私もオブジェクト指向の最初のハードルは 「マルチプル インスタンス」 を理解できるかどうかだと常々言っているクチですが、今回の質問内容は 「インスタンス」 だったかどうかが問題とは思わないです。 質問者さんは最初の投稿にあるとおり、インスタンスの作り方を知っています。 それらを除けばインスタンスというのは、基本データとあまりに変わりはありません (それらも 「すべてインスタンスだろ」 という突っ込みはなしです)。 今回はマルチプルかどうかも関係ないですし。 インスタンスを理解していないと仮定しても、基本データと同じように扱うことを考えるでしょうから、インスタンスでなくとも同じだったのでしゃないでしょうか? 同じように 「オブジェクト指向」 であることが問題となっているわけではありません。 よく間違われる人が多いのですが、「アクセス修飾子」 や 「値の受け渡しのメソッド (関数) カプセル化」 などの存在はオブジェクト指向ではなく、「構造化言語のモジュールの関係」 のお話だと思います。

    2008年11月22日 13:43
  •  じゃんぬねっと さんからの引用

    まどかさん、フォローありがとうございます。 いつも助かっております。

     

     

     じゃんぬねっと さんからの引用

    "実際インスタンスを渡すような場面が無いわけではないのですが" というのは、

    第一選択肢ではない といった前置きなのだと思います。

     

    そのとおりです。

     

    個人的にはNewした側が自身のインスタンスを渡すパターンは循環参照だという認識でいますので

    設計時に選択肢にすらならないです。

    過激なことを言えば、コンパイルエラーになってもいいんじゃないかとも思います。

    #実際困るかもしれんけど(汗

     

    似たようなやりとり(笑

    http://bbs.wankuma.com/index.cgi?mode=al2&namber=6497&KLOG=6

    2008年11月22日 14:56
  •  まどか さんからの引用
    個人的にはNewした側が自身のインスタンスを渡すパターンは循環参照だという認識でいますので設計時に選択肢にすらならないです。

     

    プログラミングの世界で問題となる (悪名が高い) 「循環参照」 とは事情が違うのではないでしょうか? 循環参照 (?) になること自体は問題ではなく、呼び出し先が呼び出し元が何者かを知っているがゆえに依存性が高くなることが問題というお話でしたよね。 まどかさんもそういう意見だったはず...

     

    # 循環参照という言葉に悪いイメージがあるのは、COM の参照カウントの循環参照だとかそういうお話が有名だからだと思います。

     

     まどか さんからの引用
    似たようなやりとり(笑
    http://bbs.wankuma.com/index.cgi?mode=al2&namber=6497&KLOG=6

     

    ここでは、はいこーん氏の意図が誤解されているようですね。 どうも似たようなレベルで誤解されているっぽいので、突っ込みを入れたいのですが ReadOnly 状態なのでこちらに書いちゃいます。

     

     trapemiya さんからの引用
    No6538 の trapemiya さんの投稿から引用:

     

    例えばOwnerプロパティなんていうのもあるし

     

    Owner プロパティは本来情報を取得するためのものではないと思います。 そもそも厳密な型ではないですし。 Owner プロパティがあるから情報を取得しても良いという発想は私にはないです。 そういう意味ではリンク先のまどかさんの発言 "OwnerのようにFrameworkで用意されているものは積極的に使いますが" はそんな場面はあるのかなぁという意味でちょっと疑問です。 今はまた考え方が変わってらっしゃるかもしれませんが。

     

    はいこーん氏の "呼び出し先が呼び出し元のインスタンスを持つのは構造上あまり良いとは言えません" の意図は、「情報取得をするために」 という暗黙の前提があっての発言でしょう (でなければ、ここではいこーん氏の主張は何ら意味がないので)。 そもそもこの部分の言葉尻だけ捉えて反論するからおかしくなったのではないでしょうか? その前にある "まあ、Form自体を渡すことは通常ないです。 Formのインスタンスそのものを渡すのではなく、参照したいものだけを渡すべきですね。" とあるとおりで、必要なものだけ最初に勝手に渡しておけということが言いたいのでしょう。 そもそも Owner プロパティは System.Windows.Forms.Form 型であって厳密な型でないから事情が違う (目的が違う == インスタンスが保持している情報を取得するためでない) んですよね (厳密な型でないがゆえに依存は生まれませんし)。

     

    もちろん情報を取得する以外に 2 つの Form の間でデータや UI に連動性がある場合はこれでは実現できません。 こういう時にイベントと DataBinding うんぬんが役立ちます。 今回の質問内容である 「Form を閉じる」 というアクションもこの連動性があるわけです。 発端となった trapemiya さんの発言にある 「値を相互に (呼び出し元相手に) やりとりしたい」 状況というのは仕様上 2 つ以上の Form が何らかの形で半リアルタイムに連動したい時です。 だから、イベント、DataBinding という単語を出して私は反論したんですね (あ~、ここの説明を省略したのがまずかったのかな...)。

     

    半リアルタイムな連動が不要な場合、たとえば 「結果セット」 が欲しい場合は、それは呼び出し元が自身が呼び出し先のインスタンスを知っていますから、勝手に取得できます。 呼び出し元が呼び出し先の情報を見るのは別に問題ないことです。

     

     いずれにせよ呼び出し先が呼び出し元に干渉するのは避けておいた方が良いという結論には直接関係のないお話かな。

     

     trapemiya さんからの引用
    呼び出し先で呼び出し元の参照を得てなければ使えないし。

     

    ちょっと意味がわかんないです。 ここでの話の流れは、呼び出し元の情報は 「必要最小限のデータだけあればいい、そしてそれは '呼び出し先から取得する' のではなく '呼び出し元から渡される' べきもの」 ということでしょう。 呼び出し先から使えなくていいと思います。 あくまで呼び出し元から勝手に渡ってくるものです。 呼び出し元が何者だなんて参照はデータが欲しいだけなのですから不要です。

     

     trapemiya さんからの引用
    そのプロパティをstaticで定義する例も世の中にはあるけど、

     

    こんな回避方法をしたコードこそ見たことないです。(^^;

     

    # 長文苦手なのでそろそろ降りようかな。 だいたい説明できているハズなので。

    2008年11月22日 16:01
  • とりあえず本題は別として、質問の部分を先に答えますね。かなりのボリュームだったので、抜けがあれば言ってください。長文にしないつもりがやっぱり長文になっちゃいました。ごめんなさい。

     

     じゃんぬねっと さんからの引用

    ん? "インターフェイスを介せば" の話はどこから飛んできたのでしょうか? 「言語仕様上のインターフェイス」 ではなく 「広義のインターフェイス」 のことでしょうか?
    だとすれば、引数にしても、保持しておく変数にしても  Form1 と互換のある 「型」 を持たなければならないという点で 「依存度」 が違うと思います。 厳密でない型であったとしても (そんな選択をする人はなかなかいないと思いますが) 概念上依存していることになります。 まどかさんの言いたいことはまさにここで、"依存関係の一方通行化" という表現がまさにここに当たると思います。 これを守ることで私は修正が両方に及ぶのを防ぐことができますという説明をしています。 「モジュールの結合度」 だけで分別してはいけないということですね。

    インターフェースに関してはまどかさんの以下の発言に対して、これは何もイベントだけの特権じゃないということが言いたかったんです。

     

    >そういう意味ではform2はform1に依存していませんよね。
    >form2 クラスとしてはだれがイベントを拾おうとしているのかさえ知りませんし。

     

    インターフェースという接着剤があれば、どのような型同士でも引っ付けることができるということが私が言おうとしたことなんですが、これで答えになっていますでしょうか?


    私がまどかさんの発言を変な風に捉えてしまったのかもしれませんが、以下のまどかさんの発言における「form2はform1に依存していませんよね」というのは、イベントを使うことによってform2というのがform1の型に捉われない疎の関係という意味に私は捉えました。どちらかというとform1はform2に依存しないという方が正確であると思いますが・・・

     

    依存関係の一方通行化に関しては、明確にそのような依存関係があれば一方通行化すべきことに異論はありません。

     

     じゃんぬねっと さんからの引用

    その部分に関しては、"兄弟のような関係のフォームが仕様上あった場合、やむなく相互で値の渡し合いをしているようなコードを見かけることがありますが" とバッチリ前提を書いています。 なぜ勝手に "どのような場合でも" という解釈をされてしまっているのでしょうか?

    こう解釈したのは、その後に「これもイベントや DataBinding などを使えば回避できます。」という文章が続いていたため、兄弟のような関係のフォームでも、イベントや DataBinding で回避すべきだと捉えたからです。しかし、これについては他のじゃんぬさんの発言で、私の解釈が誤りであったことに気づきました。

     

     じゃんぬねっと さんからの引用

    と書いていたからです。 このスレッドの流れからして Form2 は Form1 から呼び出される Form と考えるのがフツーです (何も書いていないのですから、フツーはそう捉えるでしょう)。 で、"その呼び出されちゃった Form2 から呼び出し元の Form1 のプロパティやメソッドを呼び出したくなった時" なんてのは私にはありませんし、そんなコードは書きたくありませんぜ。 という意味で書きました。

    ですので "初心者から一歩踏み出した" という結論には私は反対です。 もちろん 「この表現は上から目線だ」 なんて意味ではなく、賛成できないという意味です。 しかし真っ向から反論するのはフレームの元なので、わざと自虐的な表現にして柔らかく言ったのでした。


    初心者には高飛車に行きますよ~。という冗談はさておいて、
    "初心者から一歩踏み出した" という意味は、インスタンスを理解したらという意味で書きました。Form2からForm1のプロパティやメソッドを呼び出せるようになったらという意味ではありません。誤解を与える書き方だったようですね。すみません。
    ただ、後述しますが、私はForm2からForm1のプロパティやメソッドを呼び出すコード容認派です。容認であって、決してイベントよりも優先しろと言っていないのは、何度も繰り返している通りです。
    ちなみに「自虐的な表現にして柔らかく言ったのでした。」はわかっていました。ネットだけですが、長い付き合いですからw まぐれかもしれませんがw

     

     じゃんぬねっと さんからの引用

    Owner プロパティは本来情報を取得するためのものではないと思います。 そもそも厳密な型ではないですし。


    ここも私は許容派です。確かに厳密な型ではありませんが、使えるものなら使えばいいじゃないという考えです。同じ意味でMdiParentプロパティなんかも同様です。MDI親フォームのインスタンスをMDI子フォームに渡しますが、私はそれを普通に使います。解説にも以下のようにあります。

    「MDI 子フォームを作成するには、MDI 親フォームになる Form を子フォームの MdiParent プロパティに割り当てます。このプロパティを MDI 子フォームから使用すると、すべての子フォームに必要なグローバル情報を取得したり、すべての子フォームに対してアクションを実行するメソッドを呼び出すことができます。」

     

     じゃんぬねっと さんからの引用

    はいこーん氏の "呼び出し先が呼び出し元のインスタンスを持つのは構造上あまり良いとは言えません" の意図は、「情報取得をするために」 という暗黙の前提があっての発言でしょう (でなければ、ここではいこーん氏の主張は何ら意味がないので)。 そもそもこの部分の言葉尻だけ捉えて反論するからおかしくなったのではないでしょうか? その前にある "まあ、Form自体を渡すことは通常ないです。 Formのインスタンスそのものを渡すのではなく、参照したいものだけを渡すべきですね。" とあるとおりで、必要なものだけ最初に勝手に渡しておけということが言いたいのでしょう。


    確かにご指摘の通り、言葉尻だけを捉えて私が勝手に勘違いしていたのかもしれませんね。

     

     じゃんぬねっと さんからの引用

    今回の質問内容である 「Form を閉じる」 というアクションもこの連動性があるわけです。 発端となった trapemiya さんの発言にある 「値を相互に (呼び出し元相手に) やりとりしたい」 状況というのは仕様上 2 つ以上の Form が何らかの形で半リアルタイムに連動したい時です。 だから、イベント、DataBinding という単語を出して私は反論したんですね (あ~、ここの説明を省略したのがまずかったのかな...)。


    この連動性に関しては、私も想定していました。例えばよく以下のようなことを行います。契約データがあり、そこに毎月の請求金額データがぶら下がっているとしましょう。formAでは月単位に契約データを一覧表示します。例えば各契約の11月分の請求金額が一覧で表示されるわけです。formBでは契約単位に各月の請求金額が一覧で表示されます。例えばある契約の毎月の請求金額が一覧表示されています。この二つの画面から請求金額を変更するformCを開くとします。つまり、formA -> formCとformB -> formCの関係です。formCで請求金額を変更したら、formCを開いたままで自動的にfromAやformBの画面を変更するものとします。(だって、カッコいいじゃん)
    もちろん、イベントを使う方法が有力でしょう。しかし、イベントは発火するだけであって、formCからformAやformBの再表示の仕方までコントロールすることができません。例えば請求月を変えたのであれば、formAの一覧の抽出条件をその月に変更して検索したい場合もあるでしょうし、そうでない場合もあるでしょう。つまり、子が親を制御しなければイベントがベストで楽な方法だと思いますし、制御したいのであればイベントでは処理しきれなくなります。また、考え方としても、formAもfromBも例えばShowDataGridViewみたいなインタフェースメソッドを実装するようにすれば統一感が出ますし、クラス図を見たときにわかりやすい気がします。

     

     じゃんぬねっと さんからの引用

    ちょっと意味がわかんないです。 ここでの話の流れは、呼び出し元の情報は 「必要最小限のデータだけあればいい、そしてそれは '呼び出し先から取得する' のではなく '呼び出し元から渡される' べきもの」 ということでしょう。


    これを否定するつもりもありませんし、正しい考え方だと思います。ただ私がずっと言いたいのは、これでは処理しきれない場合の話です。って、私が頭の中で論点が飛躍しているからまずい気がしてきました。

     

     じゃんぬねっと さんからの引用

    そのプロパティをstaticで定義する例も世の中にはあるけど、
     

     


    こんな回避方法をしたコードこそ見たことないです。(^^;


    staticをやたらと使いたがる人はいます。最初の発想としては素直な発想だと思いますが、もちろん推薦するわけではありません。

     

    さて、勝手に焦点を絞ると、じゃんぬさんもまどかさんも「Form2からForm1のプロパティやメソッドを呼び出すコード」は状況によってはあり得るが、依存関係にある場合にはそうすべきではない、もしくは第一選択肢ではないと言われていると思いますが、合っていますでしょうか? 基本、ここが確認したかっただけという話もありますw もし合っていなければその理由が知りたかったのです。わかりにくくてすみません。
    さて、これについて、ほとんど私も同じ意見です。ただ、少しだけ私の方が容認というか、許容範囲が広いんじゃないかと思いました。私は今回のケースではイベントを使うのが一番スマートだと思いますが、form1のインスタンスをform2に渡すコードであっても、それを否定するほどのひどいコードだとは思わないのです。なぜならform1のインスタンスをform2へ渡すこと自体、絶対にやってはいけないことではないと思うからです。また、ケースによってはやった方が良い場合もあるでしょう。これはじゃんぬさんもまどかさんもOKですよね? まどかさんはこれは循環参照のパターンだと言われていますが、それはインスタンスを渡すことが原因ではなくて、それを利用したコードのロジックに問題があるわけでしょう?インスタンスを渡すことは.NETの標準で用意されているクラス間でも普通に行われていることですし。そう思われているから注釈が付いているのだと思いました。

     

    また、先に述べたように、form1とform2はセットでこの組み合わせしかない場合の依存関係と、そうでない場合の依存関係があると思います。例えば、form1とform2でも依存関係があり、form1aとform2の組み合わせでも依存関係がある場合です。このようにform2の依存元が変わるのであれば、依存元全てに合わせてform2を作成することは不可能です。つまり、form2は依存先にはなれるが、特定の相手を依存元としないように作成しなければなりません。これを解決する方法の一つがイベントです。しかし先に例を出したように、イベントだけで全て解決できるわけではありません。例えばform2が依存元formのプロパティに値をセットしたくなった場合や、form2が依存元formが必要とするプロパティを用意しなければならなくなった時などもあるでしょう。確かにformというクラスに限って言えば、こういうケースは稀かもしれません。しかし、絶対にあり得ないとも言えないでしょうし、formに限定しないクラスの場合は普通にあり得ます。WPFではこれを依存関係プロパティや添付プロパティで解決していますが、そのような仕組みがないWindows Formにおいては、せいぜいインターフェースを利用してGetValueやSetValueなどの汎用的なインターフェースメソッドを用意するぐらいが現実的じゃないかと思います。ただ、この場合にはWPFと違って依存先にインスタンスを渡す必要があるんですよね。だから、インスタンスを依存元から依存先へ渡すことは、まぁ、いいんじゃない?っていうのが私の考えですし、こういうコーディングはWPFを知る前からやっています。依存関係はあるけど疎なわけです。偉そうに言っているわけではなく、私が特殊なことをやっていているわけでもなく、.NETに標準で用意されている引数がインターフェース型のコンストラクタなどと同じことです。だから最初に戻りますが、私はインスタンスのやり取りに対して全般に寛容になったのでしょうね。きっと。

     

    ># 長文苦手なのでそろそろ降りようかな。 だいたい説明できているハズなので。

     

    わっ、私も・・・。でも、発端は私ですから、私は付き合わないといけませんね。でも、なんか私、話が飛躍しすぎてるような気がしてきました・・・。やっぱり。

    それに、細かい点を除いてみなさんとそんなにずれていない気がしますし、そのずれもたぶん大きなものではないと思っています。

    2008年11月23日 4:32
    モデレータ
  • 残念ながらまだ続きます。 疲れてしまうといけないので概ね意思疎通ができたところはさっくりと省略します。 引用は多いですが、私の文章は少なめになっているハズです。

     

     trapemiya さんからの引用
    インターフェースに関してはまどかさんの以下の発言に対して、これは何もイベントだけの特権じゃないということが言いたかったんです。

     

    たぶんですが、まどかさんの発言の前提条件と trapemiya さんが理解している前提条件が合致していないのではないでしょうか。

     

     まどか さんからの引用
    form2 クラスとしてはだれがイベントを拾おうとしているのかさえ知りませんし。

     

    こちらの発言の前提が、

     

     trapemiya さんからの引用
    例えばform2からform1のプロパティやメソッドを呼びたくなった

     

    だとした場合、trapemiya さんの方法では Form2 が Form1 の存在に関与することになります (仮に型を抽象的にしても関与はしています)。 しかしイベントの場合は、Form1 が Form2 を生成した時に予め設定しておけばよいわけで、Form2 には一切その都合にまつわるソースの記述が不要になります。 これが、

     

     まどか さんからの引用
    form2 クラスとしてはだれがイベントを拾おうとしているのかさえ知りませんし。

     

    の発言に繋がっているのではないかと思います。

     

     trapemiya さんからの引用
    同様にインスタンスメソッドもインターフェースを介せば疎の結合になります。

     

    この発言は 「同様 (の疎結合) にはならない」 ので間違っているのではないでしょうか。 Form2 から Form1 のインスタンス メンバに対して何らかのアクションを起こす場合、Form1 の存在に関与する必要がありますが、イベントを使う場合 Form2 は Form1 のことは何も関与する必要がありません。

     

     trapemiya さんからの引用
    インターフェースという接着剤があれば、どのような型同士でも引っ付けることができるということが私が言おうとしたことなんですが、これで答えになっていますでしょうか?

     

    ここの話題に関しては trapemiya さんの 「答え」 がまどかさんの発言に対して 『反論になっていないような気がするなぁ』 と思って、いろいろ突っ込みを入れていました。

     

     trapemiya さんからの引用
    イベントを使うことによってform2というのがform1の型に捉われない疎の関係という意味に私は捉えました。

     

    型だけではないんですよね。 型だけの問題でしたら横着な話、Form1 という型をぼやかしてしまえば同等と言えてしまいます。 型以外にもソースコードでの介入の度合いが変わってきます。 このスレッドの私の回答例では Form2 にソースを書き加える必要さえないですね。

     

     trapemiya さんからの引用
    どちらかというとform1はform2に依存しないという方が正確であると思いますが・・・

     

    私も依存については逆に書いてしまったかもしれません。 この点は申し訳ないです。

     

     trapemiya さんからの引用
    ここも私は許容派です。確かに厳密な型ではありませんが、使えるものなら使えばいいじゃないという考えです。同じ意味でMdiParentプロパティなんかも同様です。MDI親フォームのインスタンスをMDI子フォームに渡しますが、私はそれを普通に使います。解説にも以下のようにあります。

     

    私は許容できないわけでもないですが、できれば許容したくない派です。 MSDN の解説についてですが 「できます」 と書いてあるだけです。 これは 「可能」 という意味であり 「推奨」 という意味ではないので、少し理由としては弱いと思います。 百歩譲ってどうしてもやることになった場合は、Form2 から Form1 の独自メンバを呼び出そうとしている時点で System.Windows.Forms.Form 型ではなく、もう少し厳密な型で扱いたいと考えます。

     

     trapemiya さんからの引用
    もちろん、イベントを使う方法が有力でしょう。しかし、イベントは発火するだけであって、formCからformAやformBの再表示の仕方までコントロールすることができません。例えば請求月を変えたのであれば、formAの一覧の抽出条件をその月に変更して検索したい場合もあるでしょうし、そうでない場合もあるでしょう。つまり、子が親を制御しなければイベントがベストで楽な方法だと思いますし、制御したいのであればイベントでは処理しきれなくなります。また、考え方としても、formAもfromBも例えばShowDataGridViewみたいなインタフェースメソッドを実装するようにすれば統一感が出ますし、クラス図を見たときにわかりやすい気がします。

     

    "再表示の仕方までコントロールする" というか 「再表示の仕方を通知」 することはできますよね。 イベント引数の存在を忘れていませんか?

     

     trapemiya さんからの引用
    これを否定するつもりもありませんし、正しい考え方だと思います。ただ私がずっと言いたいのは、これでは処理しきれない場合の話です。って、私が頭の中で論点が飛躍しているからまずい気がしてきました。

     

    その "処理しきれない場合" に出くわしたことがないです。 いや正確には私のグループの新入社員がそういう実装をしていたのを知っていたのに見逃して許容したことはあります。 もしどうしても逃れられない場合があった時、私は仕様変更を考えるので本当の意味で出くわすことは今後もないのではないかなと思います。

     

     trapemiya さんからの引用
    さて、勝手に焦点を絞ると、じゃんぬさんもまどかさんも「Form2からForm1のプロパティやメソッドを呼び出すコード」は状況によってはあり得るが、依存関係にある場合にはそうすべきではない、もしくは第一選択肢ではないと言われていると思いますが、合っていますでしょうか?もし合っていなければその理由が知りたかったのです。わかりにくくてすみません。

     

    "状況によってはあり得るが" のところに関してはわからないので合っているかどうかの答えは出せないです。 そういう状況が思い浮かばないからだと思います。

     

     trapemiya さんからの引用
    私は今回のケースではイベントを使うのが一番スマートだと思いますが、form1のインスタンスをform2に渡すコードであっても、それを否定するほどのひどいコードだとは思わないのです。なぜならform1のインスタンスをform2へ渡すこと自体、絶対にやってはいけないことではないと思うからです。

     

    "ひどいコード" かそうでないかは主観的なものが絡むので明言しませんが、もっと 「良い方法がある」 というのを知っているのであれば 「そちらを選択すべき」 と強く主張しても良いのではないでしょうか? "絶対にやってはいけない" ではなく 「どうしてその方法を取るの?」 という主張はしても良いと思います。

     

     trapemiya さんからの引用
    また、ケースによってはやった方が良い場合もあるでしょう。これはじゃんぬさんもまどかさんもOKですよね?

     

    繰り返しになりますが、そのケースが想像できないので OK か NG かの答えが出せないです。orz

     

     trapemiya さんからの引用
    また、先に述べたように、form1とform2はセットでこの組み合わせしかない場合の依存関係と、そうでない場合の依存関係があると思います。例えば、form1とform2でも依存関係があり、form1aとform2の組み合わせでも依存関係がある場合です。このようにform2の依存元が変わるのであれば、依存元全てに合わせてform2を作成することは不可能です。

     

    そもそも "Form1 と Form2 がすでに依存関係にある" という前提が変な気がするというか、その依存の詳細がわからないのですが、ここで言いたいのは Form2 が Form1 と Form1a の 2 つの関連を持っているということですよね。 これこそイベントや DataBinding の出番なのではないでしょうか? Form1 と Form1a で Form2 の状況を今回のようにイベントで捕捉さえすれば、手を加えるのは Form2 ではないので "依存元全てに合わせてform2を作成することは不可能です。" にはならないです。 イベントは呼び出し元に当たる Form1 と Form1a と双方で捕捉でき、何をしたら良いのかという情報、またはデータそのものも通知できるので何でもできるのではないでしょうか?

     

     trapemiya さんからの引用
    つまり、form2は依存先にはなれるが、特定の相手を依存元としないように作成しなければなりません。これを解決する方法の一つがイベントです。しかし先に例を出したように、イベントだけで全て解決できるわけではありません。

     

    "先の例" というのはどれのことでしょうか? もし Form1a を加えた例の話のことであれば、何だか反論の方法がおかしいように思えます。 trapemiya さんは "これを解決する方法の一つがイベントです" と書いていますが、直後に同じ話に対して "しかし先に例を出したように、イベントだけで全て解決できるわけではありません" とも書いています。 そして↓の文章に繋げていますが、

     

     trapemiya さんからの引用
    例えばform2が依存元formのプロパティに値をセットしたくなった場合や、form2が依存元formが必要とするプロパティを用意しなければならなくなった時などもあるでしょう。

     

    この 「例えば」 で出ている前提内容がおかしいように思います。 私はデータが欲しいだけならイベントや DataBinding で代用可能であるという説明を何度もしています。 私の説明に反論するのであれば、代用できない例を提示する必要がありませんか? それをすっとばして、"例えばform2が依存元formのプロパティに値をセットしたくなった場合" というトンデモ前提を説明なしにおくのは反則じゃないでしょうか? "したくなった場合" という前提でもう私の論が潰されていますもの。 "したくなった" 時点でもう私の方法を取らないですもの。

     

    喩えるなら、trapemiya さんの家に 13 時までに到着しなければならないとします。 車だと渋滞してしまい間に合わないことは前もってわかっていました。 電車で行けば間に合うこともわかっていました。 この場合電車で行くべきですが、この人、レクサス LS を買ったばかりで、どうしても "車に乗りたくなった場合" はその人は車に乗っていきますよね? と言われたら 『ああ、その人はそういう人なので車で行くかもしれませんね』 としか言いようがないです。

     

    P.S.

    で、このおかしいと思える内容を辿っていくとどうもイベント引数の存在を忘れているところに行き着くのではないかなと思います。 もしそうであれば、自分で言うのも何ですが私は言いすぎですね。 申し訳ないです。 私も何でもかんでも無理にイベントや DataBinding を使うわけではないので、どうしてもやむを得ない場合があるという仮定であれば使わないと思います。 問題はその仮定が想像できないというところです。
    WPF に関しては話題が変わってくると思うので省略させて頂きました。

    2008年11月23日 9:37
  •  じゃんぬねっと さんからの引用

    プログラミングの世界で問題となる (悪名が高い) 「循環参照」 とは事情が違うのではないでしょうか? 循環参照 (?) になること自体は問題ではなく、呼び出し先が呼び出し元が何者かを知っているがゆえに依存性が高くなることが問題というお話でしたよね。 まどかさんもそういう意見だったはず...

     

    A クラスでNew B、B クラスのコンストラクタ引数がA型

    私はこのパターンを循環参照というあくまで自分のポリシーとして認識しており

    そういう意味で選択肢にすらならないということです。

     

    そうすることもあると言ったのは

    たとえばコレクション クラスとメンバなど非常に密接で、

    かつ連携が大量にある場合(イベントをたくさん作らなくちゃいけない)などに

    半分面倒で今回のパターンのようにインスタンスを渡すことはあります。

     

    MDIParentが出ましたが、

    DIm f As ChildForm

    f.MDIParent = Me

    と、普通にやってました。(汗

     

    なんか言ってることとやってることが違いますね。。。

    2008年11月23日 12:55
  •  じゃんぬねっと さんからの引用

    残念ながらまだ続きます。 疲れてしまうといけないので概ね意思疎通ができたところはさっくりと省略します。 引用は多いですが、私の文章は少なめになっているハズです。

     

    同じくそうしますね。


     じゃんぬねっと さんからの引用

     trapemiya さんからの引用
    同様にインスタンスメソッドもインターフェースを介せば疎の結合になります。

    この発言は 「同様 (の疎結合) にはならない」 ので間違っているのではないでしょうか。 Form2 から Form1 のインスタンス メンバに対して何らかのアクションを起こす場合、Form1 の存在に関与する必要がありますが、イベントを使う場合 Form2 は Form1 のことは何も関与する必要がありません。


    確かにform2がform1のインスタンスを持つという意味ではイベントよりも密ですが、インターフェースを介しますのでform1の厳密な型がform2に存在しないという意味では疎ですので、そのレベルでform2が抽象化できていれば良いという意味で疎と書きました。

     

     じゃんぬねっと さんからの引用

    型だけではないんですよね。 型だけの問題でしたら横着な話、Form1 という型をぼやかしてしまえば同等と言えてしまいます。 型以外にもソースコードでの介入の度合いが変わってきます。 このスレッドの私の回答例では Form2 にソースを書き加える必要さえないですね。

    確かにそうなんですが、独自のイベントを設けた場合にはform2のソースを改修しなければなりません。そういう意味ではイベントを利用したからといって、ソースコードに必ず手が入らないわけではありません。でも、標準の用意されているイベントを利用する限りは確かに生産性は良いですね。その意味もあって、イベントを使う方法が、このスレの質問の最適な回答だと思っています。

    型をぼやかすということについてはよくわかりませんでした。具体的にはどういうことを言われているのでしょうか?

     

     じゃんぬねっと さんからの引用

    私は許容できないわけでもないですが、できれば許容したくない派です。 MSDN の解説についてですが 「できます」 と書いてあるだけです。 これは 「可能」 という意味であり 「推奨」 という意味ではないので、少し理由としては弱いと思います。 百歩譲ってどうしてもやることになった場合は、Form2 から Form1 の独自メンバを呼び出そうとしている時点で System.Windows.Forms.Form 型ではなく、もう少し厳密な型で扱いたいと考えます。

    ここが一番聞きたいところなんですが、許容したくない理由は何なのでしょうか? なぜform2からform1のメンバを参照してはいけないのでしょうか? たぶん、一番の意見の相違はこの部分だと思うんです。まどかさんはコンパイルエラーにしてほしいぐらい嫌っていましたし、純粋にこの理由がわからないのです。私なんか百歩も譲らずやっちゃいます。
    System.Windows.Forms.Form 型で扱いたくないのは私も同意見ですが、厳密な型で扱うようにすると依存度が高まってしまいませんか? 私は繰り返し述べているようにインターフェースでラップして、全てインターフェース型として扱いたいと考えています。

     

     じゃんぬねっと さんからの引用

    "再表示の仕方までコントロールする" というか 「再表示の仕方を通知」 することはできますよね。 イベント引数の存在を忘れていませんか?


    さすがに忘れてはいませんが、イベント引数を使うのは不適切だと考えていました。なぜなら、特定のイベントハンドラを対象にしたイベント引数を実装するべきではないと思うからです。しかし、じゃんぬさんに言われて改めて考えてみたのですが、イベント引数をobject型にしてその都度いろんなものを突っ込むのであれば、特定のイベントハンドラを対象とせず、from2の抽象化を保てることに気づきました。インターフェースメソッドの引数もobject型にしなければなりませんから、イベントで処理できなくてインターフェースメソッドではうまく処理できるように書いたのは誤りでした。ごめんなさい。

    イベントはデリゲート型の登録ですし、インターフェースメソッドにしてもその時点でシグニチャが決まってしまいますから、そこに関しては全く同じですね。つまり、汎用的にしようと思えばobject型を引数にするしかありません。

     

     じゃんぬねっと さんからの引用

    その "処理しきれない場合" に出くわしたことがないです。


    form2からform1のパブリックなプロパティを操作する状況に出くわしたことがないという意味なのでしょうか? イベントだけでform1のプロパティを操作されているとも思えないのですが・・・。 それともイベントに絡むメソッドの実行に限ったことなのでしょうか?

     

     じゃんぬねっと さんからの引用

    そもそも "Form1 と Form2 がすでに依存関係にある" という前提が変な気がするというか、その依存の詳細がわからないのですが、ここで言いたいのは Form2 が Form1 と Form1a の 2 つの関連を持っているということですよね。 これこそイベントや DataBinding の出番なのではないでしょうか? Form1 と Form1a で Form2 の状況を今回のようにイベントで捕捉さえすれば、手を加えるのは Form2 ではないので "依存元全てに合わせてform2を作成することは不可能です。" にはならないです。 イベントは呼び出し元に当たる Form1 と Form1a と双方で捕捉でき、何をしたら良いのかという情報、またはデータそのものも通知できるので何でもできるのではないでしょうか?


     "依存元全てに合わせてform2を作成することは不可能です。" に関しては言い過ぎたようです。先に述べたように、object型で渡せば可能ですね。ごめんなさい。インターフェースメソッドにすれば厳密な型で渡せると錯覚もしていました。ちょっとWPFのプロパティシステムがダブったかな?w

     

     じゃんぬねっと さんからの引用

     trapemiya さんからの引用
    例えばform2が依存元formのプロパティに値をセットしたくなった場合や、form2が依存元formが必要とするプロパティを用意しなければならなくなった時などもあるでしょう。


    この 「例えば」 で出ている前提内容がおかしいように思います。 私はデータが欲しいだけならイベントや DataBinding で代用可能であるという説明を何度もしています。 私の説明に反論するのであれば、代用できない例を提示する必要がありませんか?


    まず、「例えばform2が依存元formのプロパティに値をセットしたくなった場合」についてですが、これをイベントで処理する考えは私の中には全くありませんでした。私の中では常識だったので例を出すまでもありませんでした。確かに技術的に実現する方法はわかりますが、なぜ、そこまでされるのかがわかりません。ですから、技術的にイベントではできないという意味ではなく、普通はイベントで処理しないだろうという私の中の常識が書かせたものです。MdiParentのところで書いたのと同じ質問になりますが、イベントもしくはDataBindingで代用される理由は何なのでしょうか? ひょっとして私の中での常識が崩れ去るかも・・・
    「form2が依存元formが必要とするプロパティを用意しなければならなくなった時」、これについては既にごめんなさいしてる通りです。

    2008年11月23日 15:49
    モデレータ
  •  まどか さんからの引用

    たとえばコレクション クラスとメンバなど非常に密接で、

    かつ連携が大量にある場合(イベントをたくさん作らなくちゃいけない)などに

    半分面倒で今回のパターンのようにインスタンスを渡すことはあります。

     

    まどかさんは循環参照になるからというポリシーでそうされているようですが、こうやってイベントで処理しなければならないというのは何かの教科書に載っているのでしょうか? どのような弊害があるのでしょうか? また、循環参照となる具体的な例を教えていただけませんか? 半分面倒でインスタンスを渡した場合に、循環参照にならないように何か工夫されていますか?

     

    質問ばかりで申し訳ありません。

     

     まどか さんからの引用

    MDIParentが出ましたが、

    DIm f As ChildForm

    f.MDIParent = Me

    と、普通にやってました。(汗

     

    なんか言ってることとやってることが違いますね。。。

     

    でもこれは好む好まざる関係なく、こうせざるを得ないですから。MDIアプリケーション作るためには。

    問題はここから先で、私は普通にMdiParentプロパティからMDI親フォームにあるコントロールや設定情報を参照したり設定したりしますが(実際にはコントロールはメソッド経由)、まどかさんもじゃんぬさんも強い抵抗があってイベント経由なわけですよね・・・。

    ちなみにASP.NETだとparentプロパティでどんどん親のインスタンスを簡単に手に入れられるんで、そのインスタンスを直接弄ることはよくありますし、海外の掲示板でもそういう回答はよく見かけます。そのためのparentプロパティなんでしょうから。

    Windows Formだとなんでダメなのかなぁ? なんか勘違いしてるかなぁ?

    2008年11月23日 16:01
    モデレータ
  • 真に残念ながら今回も長文です。 いやがらせのように説明が重複していますがわざとですw いや、大真面目は話、ここまでくると回りくどくてもしっかり前提を書いて説明をした方が良いかなと思いました。

     

     trapemiya さんからの引用
    確かにそうなんですが、独自のイベントを設けた場合にはform2のソースを改修しなければなりません。そういう意味ではイベントを利用したからといって、ソースコードに必ず手が入らないわけではありません。

     

    "ソースコードに手が入らない" の部分については、ちゃんと前提として書いているとおり 「このスレッドの私の回答例」 でのお話ですが、これは下記の説明をするのが面倒で無理矢理納得させようと書いたもので誤解を招く発言でした。 とても真摯さを書く発言であったことをお詫びします。

     

    これは 『Form2 のソースに手が加わるという点で同じじゃないか』 という意味だと思いますが、独自のイベントであったにしろ加えられるコードはデータ以外は Form2 の中で完結している点で優れています。 その独自のイベントを捕捉する側 (今回だと Form1) を意識せず、インスタンスさえ必要とせず、ただイベントを起こしているだけですよね (誤解がないように説明しておきますが、放り込むデータというレベルでは優劣の差はありません。 メソッドで渡すにしてもイベント引数で渡すにしても放り込むデータには変わりがありません)。 逆に trapemiya さんの手法である Form1 (呼び出し元) への独自メソッドや独自プロパティの呼び出しで対応する場合は Form1 (もしくは互換性のある型) の記述とインスタンス (参照) が必要となります。 無駄な参照はない方が安全です。 ただ、ここに関してはそれほど重要でないような気はします。

     

     trapemiya さんからの引用
    型をぼやかすということについてはよくわかりませんでした。具体的にはどういうことを言われているのでしょうか?

     

    先にも書いたとおりで、(たとえばですが) System.Windows.Forms.Form 型を (定義では) 用いるということですね。

     

     trapemiya さんからの引用
    ここが一番聞きたいところなんですが、許容したくない理由は何なのでしょうか? なぜform2からform1のメンバを参照してはいけないのでしょうか? たぶん、一番の意見の相違はこの部分だと思うんです。

     

    これはすでに説明済みだと思うのですが、trapemiya さんの方法だと呼び出し先 (Form2) で何を呼び出すかを意識する必要があります。 これによって Form2 は自身以外の外部の存在について (型がどうであれ) 記述する必要がありインスタンスも必要です。 イベントの場合は通知を受け取りたい対象のインスタンスを必要としませんし、必要な情報を通知するだけです。 これにより、イベントを捕捉する側 (今回だと呼び出し元 | Form1) 自身が勝手にデータが受け取れる仕組みを自分自身で作れるのが強みです。 また先の trapemiya さんの例にあった Form2 と連動する Form が増えた場合 (Form1a を例として出していたお話) でも Form2 は何も改変しなくて済みます。 とにかく呼び出し元が一方的に支配している状況を作れるの点で違います。 私にはこれ以上、上手に説明することはできないと思います。

     

     trapemiya さんからの引用
    System.Windows.Forms.Form 型で扱いたくないのは私も同意見ですが、厳密な型で扱うようにすると依存度が高まってしまいませんか? 私は繰り返し述べているようにインターフェースでラップして、全てインターフェース型として扱いたいと考えています。

     

    (これは 「百歩譲ってどうしてもやることになった場合」 のお話ですので、あまり有意義ではないですが)

    "厳密な型" というより、System.Windows.Forms.Form よりは厳密な型の方が良いだろうという意味と捉えてください。 将来を考えて Interface にすることもあれば、今後どう考えても Form1 からしか利用しないなと判断した場合は敢えて Form1 という強い型を使った方が良い場面もあるでしょう。 いくら型を弱くしても、何に利用されるかを意識しなくてはいけないような場合 (今回のような場合) 敢えて型を強くして依存性を高めた方が明示できて良いという考えもあります (.NET は型が主役)。 仮に型を弱くしても利用方法は同じであり、(今回の場合だと) Form1 という存在 (インスタンス) が必要なわけですから弱い型にする必要がないとも言えます。 ただし何度も言うようにこれは 「百歩譲ってどうしてもやることになった場合」 のお話であり、今回の話の筋とは少し違う部分ですので、あまり話を広げても意味はないと思います。

     

     trapemiya さんからの引用
    さすがに忘れてはいませんが、イベント引数を使うのは不適切だと考えていました。なぜなら、特定のイベントハンドラを対象にしたイベント引数を実装するべきではないと思うからです。

     

    これは真面目なお話ですか? もしそうなら System.EventArgs の派生クラスが一斉に泣き出すでしょうね。 たとえば FormClosingEventArgs なんかは特定のイベントを対象にしたイベント引数の型です。

     

     trapemiya さんからの引用
    しかし、じゃんぬさんに言われて改めて考えてみたのですが、イベント引数をobject型にしてその都度いろんなものを突っ込むのであれば、特定のイベントハンドラを対象とせず、from2の抽象化を保てることに気づきました。

    んんん? なぜ object 型なんてのが出てきたのでしょう? イベント引数はイベントの送信元を表す System.Object (sender) と、そのイベントの情報 System.EventArgs (e) と互換のある型とのセットが一般的でありガイドラインにも記載されています。 イベント引数は System.EventArgs と互換のある型にすれば良く object なんて用いるのは論外です。

     

     trapemiya さんからの引用
    インターフェースメソッドの引数もobject型にしなければなりませんから、イベントで処理できなくてインターフェースメソッドではうまく処理できるように書いたのは誤りでした。ごめんなさい。イベントはデリゲート型の登録ですし、インターフェースメソッドにしてもその時点でシグニチャが決まってしまいますから、そこに関しては全く同じですね。つまり、汎用的にしようと思えばobject型を引数にするしかありません。

     

    独自のイベントである時点で、そのレベルで汎用的にする必要はないです。 汎用的にするデメリットはあってもメリットはありません。 そんなことをしてしまえば、イベントを捕捉する側の実装が非常に面倒で無意味なものになってしまいます。 型を弱くしてしまえば良いというものではないです (むしろ型は基本的に強くすべきです)。

     

     trapemiya さんからの引用
    form2からform1のパブリックなプロパティを操作する状況に出くわしたことがないという意味なのでしょうか? イベントだけでform1のプロパティを操作されているとも思えないのですが・・・。それともイベントに絡むメソッドの実行に限ったことなのでしょうか?

     

    これも前提のすり合わせができていないがためにあがった疑問ですね。 これは 「Form1 から呼び出された Form2 が自身の情報を呼び出し元である Form1 に渡したい場合に、Form2 で Form1 (もしくはその互換性のある型) を使ってメソッドやプロパティで渡すしか方法がない!!」 なんていう状況に出くわしたことがないという意味です。

     

     trapemiya さんからの引用
    "依存元全てに合わせてform2を作成することは不可能です。" に関しては言い過ぎたようです。先に述べたように、object型で渡せば可能ですね。ごめんなさい。インターフェースメソッドにすれば厳密な型で渡せると錯覚もしていました。ちょっとWPFのプロパティシステムがダブったかな?w

     

    WPF もオブジェクト指向もクラスも関係のない部分で、構造化言語のモジュールの概念と同等な部分ではないかと思います。

     

     trapemiya さんからの引用
    まず、「例えばform2が依存元formのプロパティに値をセットしたくなった場合」についてですが、これをイベントで処理する考えは私の中には全くありませんでした。私の中では常識だったので例を出すまでもありませんでした。確かに技術的に実現する方法はわかりますが、なぜ、そこまでされるのかがわかりません。

     

    (一応例示をお願いしているので例示をして欲しかったのですが...)
    これも前提のすり合わせができていないがためにあがった疑問ですね。 このご意見は trapemiya さんが 『じゃんぬという奴は、呼び出し先の情報を呼び出し元に返したい場合、何が何でもイベントや DataBinding で処理したがる困ったやつ』 だと思っているからこその意見ではないでしょうか?w であれば幸いです。 なぜならそのレベルであればたぶん誤解がとけるからです。

     

    まず "そこまで" なんて言われるほど大げさなものではないです。 なぜならイベントや DataBinding を用いる場面というのは、今回の例のように 「半リアルタイムな Form 間の連動」 を目的としている場面のみでしか用いないからです (少なくとも私には 「呼び出し先が呼び出し元の都合を考えてメソッドやプロパティの呼び出しを考えてあげる」 (+ 場合によってはわざわざ Interface を作る) という方が大げさというか面倒に感じます)。

     

    それ以外の場合、つまりリアルタイム性がない場合で Form2 にある情報を呼び出し元に渡したい時は、イベントや DataBinding を必要としないと思います。 わかりやすい例をあげると、Form1 から Form2 を ShowDialog メソッドで呼び出した場合があげられるでしょう。 これはイベントや DataBinding を使わなくても Form1 側で勝手に Form2 に必要な情報を渡すことができ、そして回収も容易にできます。 今回のディベートの発端となった trapemiya さんご自身の発言を思い出してみてください。

     

     trapemiya さんからの引用
    他のケースでform1とform2をもっと密接にしたくなった時、例えばform2からform1のプロパティやメソッドを呼びたくなった時、きっと役に立ちます。どうプログラミングしてよいかわからないというのは、このインスタンスが協力しあって動いている世界を想像できないからじゃないかと思います。

     

    この発言にバッチリ明記されている 「form2 (呼び出し先) からform1 (呼び出し元) のプロパティやメソッドを呼びたくなった時」 に関して、私はイベントや DataBinding で代用した方が良い場面以外想像できないと言っているのです。 そしてそれが存在するのであれば具体例を挙げてくださいというお願いも間接的にしています。 そもそも発端となった発言の何が気にかかるかと言えば、呼び出し先が呼び出し元の都合を考えていることに尽きます。

     

    ですので、そもそも ShowDialog メソッドを実行後、呼び出し元が勝手に値を回収すれば解決できるような場面でさえも、『イベントや DataBinding を使うべき!!』 なんてムチャクチャなことを言っているわけではないのです。 たぶん誤解があるとすればこのあたりじゃないかなと思います。

     

     trapemiya さんからの引用
    ですから、技術的にイベントではできないという意味ではなく、普通はイベントで処理しないだろうという私の中の常識が書かせたものです。MdiParentのところで書いたのと同じ質問になりますが、イベントもしくはDataBindingで代用される理由は何なのでしょうか?

     

     「form2 (呼び出し先) からform1 (呼び出し元) のプロパティやメソッドを呼びたくなった時」 に、なぜイベントで実装したがるかについては呼び出し先で呼び出し元のメンバや都合をなるべく考えたくないからです。 そしてその 「都合」 は型が強いか弱いかなどで分別するのではなく、他のクラスの 「メソッド」 「プロパティ」 が書かれているかいないかの方が重要であると申し上げているのです。 なぜここが重要かと言えば、まどかさんも仰っている 「一方向性」 が守られるからです。 一方向性のメリットは (私には) わかりやすい、改変が楽、実装自体も面倒でない、仕様変更にも対応しやすい、別の案件で流用する時に切り離しが楽であるなどなどが挙げられます。 まあ第三者にとってはそこまで強く主張するほどのものではないかもしれません。 センスの問題もあるでしょうから、私にとってわかりやすいことがわかりにくいかもしれません。 私もここまで力を入れて長文を書いているのは強く主張したいからではなく正しい内容を伝えたいからです。 つまり今は誤解を解きたいから頑張っちゃってるわけなんですよね。 誤解がないところまですり合わせが出来た上で結論が変わらなければ、人それぞれなんだなという結論に達するのみです。

     

    ここ 2, 3 回のやりとりで思ったのですが、どうも前提のすり合わせが出来ていないように思います。 私の発言内容は特に断りがない場合は、発端となった trapemiya さんの発言が前提となっているとお考えください。 毎回前提をくどくど書いていると今以上に長文になるので、言わずもがなと思われる部分については前提を省略しています。 今回は誤解を説明するために新たな誤解を招いてはいけないと思い、必要以上に回りくどい説明をしたため重複した説明が多くなり長文になりましたが、たぶんこれで疑問は晴れると思います。 私の疑問については答えてくださっていないところがありますが (例示して欲しい件) 具体例をあげるのが難しいということは、私のスタイルで問題になることは滅多にないと考えることができるので、この点は満足です。

     

    ちなみに飲酒しながらの投稿となりますので、日本語でおkなところがあったらお許しください。 酒が入っているわりにはまだまともに書いている方だと (酔っ払っている今は) 自画自賛しています。 酔いが冷めた時には後悔しているかもしれません。

    2008年11月23日 19:12
  •  trapemiya さんからの引用

    まどかさんは循環参照になるからというポリシーでそうされているようですが、こうやってイベントで処理しなければならないというのは何かの教科書に載っているのでしょうか?

     

    オブジェクト指向を意識して作りますので、抽象化を第一としています。

    イベントで処理しなければならないという限定的なものではありませんが

    form1 でform2 をNewしている時点、つまりform1にform2という型が記述してある時点で

    参照(依存)の一方通行の方向が決まります。

    なので、form2のコードにform1という型を記述することはまずありません。

     

     trapemiya さんからの引用

    問題はここから先で、私は普通にMdiParentプロパティからMDI親フォームにあるコントロールや設定情報を参照したり設定したりしますが(実際にはコントロールはメソッド経由)、まどかさんもじゃんぬさんも強い抵抗があってイベント経由なわけですよね・・・。

     

    先に書いたようなフォームの表示のしかたは型にはまって自然にやってしまってますが

    #これに関しては言ってることと矛盾してるのはわかってます。

    #こちらの主張からすると、MDIChildren.Addとするべきなのでしょうね。

    少なくともOwnerForm系を使おうとはしないです。

    MDI子フォームで連携しなければならない場面が出たときは、イベントで親を経由するようにしますね。

    まぁ、この場合子フォーム間で情報を受け渡していたとすれば

    情報の定義が誤りか、MDIであること自体が誤りであることが多いですが。

     

    インターフェースについても、今回の場合では考えません。

    form1 と form2 がお互いに依存していない場合において考えます。(純粋な第三者)

     

    VB6では参照を持ち合っていると確実に終了時にメモリリークしました。

    #コケはしませんが、解放しようとするインスタンスが保持する参照を解放しようとしてそのインスタンスが保持する参照。。。

    #というように終了するまで数分かかります。

    そういう意味では、その場合でも普通に動作するというふれこみのFrameworkには微妙に違和感があったりします。

     

    見解の違いは、私とじゃんぬさんはクラスを閉じようとするのを第一としますが

    trapemiya さんはあるものは活用しようという、第一ポリシーの違いなのでしょう。

    私は若干 「Not べき」 が入ってますが。

    2008年11月23日 19:30
  •  じゃんぬねっと さんからの引用

    真に残念ながら今回も長文です。 いやがらせのように説明が重複していますがわざとですw いや、大真面目は話、ここまでくると回りくどくてもしっかり前提を書いて説明をした方が良いかなと思いました。


    いや、確かにその通りです。私も勝手に飛躍して前提を超えていたところが多々あるようです。

     

     じゃんぬねっと さんからの引用

    これは 『Form2 のソースに手が加わるという点で同じじゃないか』 という意味だと思いますが、独自のイベントであったにしろ加えられるコードはデータ以外は Form2 の中で完結している点で優れています。
    その独自のイベントを捕捉する側 (今回だと Form1) を意識せず、インスタンスさえ必要とせず、ただイベントを起こしているだけですよね (誤解がないように説明しておきますが、放り込むデータというレベルでは優劣の差はありません。 メソッドで渡すにしてもイベント引数で渡すにしても放り込むデータには変わりがありません)。 逆に trapemiya さんの手法である Form1 (呼び出し元) への独自メソッドや独自プロパティの呼び出しで対応する場合は Form1 (もしくは互換性のある型) の記述とインスタンス (参照) が必要となります。 無駄な参照はない方が安全です。 ただ、ここに関してはそれほど重要でないような気はします。

    コード的に見ればインターフェースを使った方法もイベントと同様にForm2の中で完結しています。Form1が来ようが新しいForm3が来ようが、Form2のソースに変更が一切ないというのはイベントど同様です。焦点となるのは、参照をForm2の中に持つか持たないかということになるように感じました。後でまどかさんも述べられていますが、ここが私との一番の考え方の差なんだなぁと思いました。決して自分の考えが正しいという意味ではありません。申し訳ないですが、今のところ自分でも結論が出ていないです。結論というより整理ですね。優劣を付けるのではなく、こういう場合にはイベント、こういう場合にはインターフェースということになるんだろうなという想像を何となくしています。

     

    "無駄な参照はない方が安全です。 ただ、ここに関してはそれほど重要でないような気はします。"と言われていますが、無駄な参照は確かに要りませんが、インターフェースを使用する以上、いや、その概念から言って必要なので、無駄だとは感じていません。ただ、後半でそれほど重要でないと言われていますので、その辺りの感覚は私と近いのかなと想像しました。

     

    私はイベントで完全に独立させてしまうよりも、関連あるオブジェクトのグループはインターフェースで縛りたい方です。また、感覚的にはイベントで完全に独立したインスタンス同士が通信のみで協力して仕事をし合うのではなく、インターフェースで繋がり、一つのオブジェクトのように機能することもイメージします。例えば、合体ロボであったり、掃除機の先のアタッチメントであったりするようにです。
    あっ、もちろんイベントを一切使わないというわけではありませんし、普通に使いますが、合体ロボのイメージのところにまでは使わないというか、その辺りのポリシーがみなさんと違うんだと思います。いいきっかけですの、いろいろ考え直してみようと思います。

     

     じゃんぬねっと さんからの引用

    先にも書いたとおりで、(たとえばですが) System.Windows.Forms.Form 型を (定義では) 用いるということですね。


    了解です。

     

     じゃんぬねっと さんからの引用

    これはすでに説明済みだと思うのですが、trapemiya さんの方法だと呼び出し先 (Form2) で何を呼び出すかを意識する必要があります。 これによって Form2 は自身以外の外部の存在について (型がどうであれ) 記述する必要がありインスタンスも必要です。 イベントの場合は通知を受け取りたい対象のインスタンスを必要としませんし、必要な情報を通知するだけです。 これにより、イベントを捕捉する側 (今回だと呼び出し元 | Form1) 自身が勝手にデータが受け取れる仕組みを自分自身で作れるのが強みです。 また先の trapemiya さんの例にあった Form2 と連動する Form が増えた場合 (Form1a を例として出していたお話) でも Form2 は何も改変しなくて済みます。 とにかく呼び出し元が一方的に支配している状況を作れるの点で違います。 私にはこれ以上、上手に説明することはできないと思います。

    これについては既に述べた通りですが、Form2でインスタンスを持つ以外は同じだと思います。確かにForm2では外部の存在を記述する必要はありますが、これもイベントと同様、インターフェース型で一度記述してしまえば後は改変する必要がありません。たぶん、そのインターフェース型を記述するのも嫌だということだと想像するのですが、イベントにしても独自のイベントなら記述しなければならないわけで、そこは同じですが、インターフェースだとその先のメソッド名やプロパティ名まで書かなきゃいけないところで独立性が無くなるということなのでしょうか? でも、これも既に述べたとおり、あえて私はそれを求めることがあります。

     

     じゃんぬねっと さんからの引用

    (これは 「百歩譲ってどうしてもやることになった場合」 のお話ですので、あまり有意義ではないですが)

    "厳密な型" というより、System.Windows.Forms.Form よりは厳密な型の方が良いだろうという意味と捉えてください。 将来を考えて Interface にすることもあれば、今後どう考えても Form1 からしか利用しないなと判断した場合は敢えて Form1 という強い型を使った方が良い場面もあるでしょう。 いくら型を弱くしても、何に利用されるかを意識しなくてはいけないような場合 (今回のような場合) 敢えて型を強くして依存性を高めた方が明示できて良いという考えもあります (.NET は型が主役)。 仮に型を弱くしても利用方法は同じであり、(今回の場合だと) Form1 という存在 (インスタンス) が必要なわけですから弱い型にする必要がないとも言えます。 ただし何度も言うようにこれは 「百歩譲ってどうしてもやることになった場合」 のお話であり、今回の話の筋とは少し違う部分ですので、あまり話を広げても意味はないと思います。


    ここについては了解です。確かに言われているように.NETでは型が主役ですので、私もあまり弱い型にしたくありません。

     

     じゃんぬねっと さんからの引用

    これは真面目なお話ですか? もしそうなら System.EventArgs の派生クラスが一斉に泣き出すでしょうね。 たとえば FormClosingEventArgs なんかは特定のイベントを対象にしたイベント引数の型です。


    ごめんなさい。ここは説明をすっとばしました。依存元が不定である以上、System.EventArgs の派生クラスをどのように作っていいのかがわからないというのが言いたかったのです。しかし、System.EventArgs の派生クラスでobject型を返すようになっていればその派生クラスは汎用的に使えるなというのが言いたかったんです。書き方も不適切だったかもしれません。

     

     じゃんぬねっと さんからの引用

    これも前提のすり合わせができていないがためにあがった疑問ですね。 これは 「Form1 から呼び出された Form2 が自身の情報を呼び出し元である Form1 に渡したい場合に、Form2 で Form1 (もしくはその互換性のある型) を使ってメソッドやプロパティで渡すしか方法がない!!」 なんていう状況に出くわしたことがないという意味です。

    これは私の前回謝った不適切な例に起因していると思います。イベントではできない場合を考えたつもりが、失敗しました。(^^;

     

     じゃんぬねっと さんからの引用

    (一応例示をお願いしているので例示をして欲しかったのですが...)
    これも前提のすり合わせができていないがためにあがった疑問ですね。 このご意見は trapemiya さんが 『じゃんぬという奴は、呼び出し先の情報を呼び出し元に返したい場合、何が何でもイベントや DataBinding で処理したがる困ったやつ』 だと思っているからこその意見ではないでしょうか?w であれば幸いです。 なぜならそのレベルであればたぶん誤解がとけるからです。


    例としては、Form2を閉じないままForm1にForm2の操作の結果を反映させたい場合です。例えば伝票入力Form1の画面があり、その画面を閉じないまま連続でデータを入力します。Form1では半リアルタイムで一覧が更新され、最大伝票番号なども更新します。ここを何が何でもイベントや DataBinding で処理されようとしているように受け取りました。私はインスタンス経由でもいいんじゃない?と思っていましたので、その理由が知りたくてここまで長い話にさせてしまっているのです。今はポリシーの違いかな?と思い始めています。trapemiyaはインスタンスで処理しようとしているとんでもない奴だと思われるかもしれませんが、今のところ私にはそれほどいけないことだとは思えないのです。form2でインスタンスを持つことがそれほどいけないことだとは思えないのです。

     

     じゃんぬねっと さんからの引用

    それ以外の場合、つまりリアルタイム性がない場合で Form2 にある情報を呼び出し元に渡したい時は、イベントや DataBinding を必要としないと思います。 わかりやすい例をあげると、Form1 から Form2 を ShowDialog メソッドで呼び出した場合があげられるでしょう。 これはイベントや DataBinding を使わなくても Form1 側で勝手に Form2 に必要な情報を渡すことができ、そして回収も容易にできます。 今回のディベートの発端となった trapemiya さんご自身の発言を思い出してみてください。


    リアルタイム性が無い場合にはその通りだと思います。

     

     じゃんぬねっと さんからの引用

    この発言にバッチリ明記されている 「form2 (呼び出し先) からform1 (呼び出し元) のプロパティやメソッドを呼びたくなった時」 に関して、私はイベントや DataBinding で代用した方が良い場面以外想像できないと言っているのです。 そしてそれが存在するのであれば具体例を挙げてくださいというお願いも間接的にしています。 そもそも発端となった発言の何が気にかかるかと言えば、呼び出し先が呼び出し元の都合を考えていることに尽きます。

    状況によっては呼び出し先が呼び出し元の都合を考えることは何も悪いことではないと思います。呼び出し元と呼び出し先が完全に独立していることをじゃんぬさんやまどかさんは好まれるようですが、私はそうでもありません。同じグループというか、おなじ範囲でオブジェクト同士が仕事をするのであれば、そこまでの独立性は求めません。むしろ同じグループなんだから協力し合って働くのが効率的だと考えますし、グループ内に制約を導入したくも思います。もちろん、グループが違えば完全な独立性を求めます。先にMDIフォームの時に話が出ましたが、System.Windows.Forms.Form でつながるのか、もっと厳密な型でつなげてしまうのか、その場合場合によるように考えています。

     

     じゃんぬねっと さんからの引用

    「form2 (呼び出し先) からform1 (呼び出し元) のプロパティやメソッドを呼びたくなった時」 に、なぜイベントで実装したがるかについては呼び出し先で呼び出し元のメンバや都合をなるべく考えたくないからです。 そしてその 「都合」 は型が強いか弱いかなどで分別するのではなく、他のクラスの 「メソッド」 「プロパティ」 が書かれているかいないかの方が重要であると申し上げているのです。 なぜここが重要かと言えば、まどかさんも仰っている 「一方向性」 が守られるからです。 一方向性のメリットは (私には) わかりやすい、改変が楽、実装自体も面倒でない、仕様変更にも対応しやすい、別の案件で流用する時に切り離しが楽であるなどなどが挙げられます。


    その通りですし、そこは理解しているつもりです。私も書き進めながら気づいたのですが、例えばDataGridViewを書き換えるメソッド名は統一しようとか、そういう方に頭が行っているようです。だから普段は自然とイベントよりもインターフェースを多用するのかもしれません。極端な話、trapemiyaインタフェースを誰もが実装せよと王様気分なのかもしれません。もちろん、私一人の中ですよw だから呼び出し先が呼び出し元を考慮してメソッド名が決まってしまうのですが、むしろ私はこれを求める場合があるし、じゃんぬさんらはいかなる場合でも求めていないということなんですね。たぶん。

     

     じゃんぬねっと さんからの引用

    私もここまで力を入れて長文を書いているのは強く主張したいからではなく正しい内容を伝えたいからです。 つまり今は誤解を解きたいから頑張っちゃってるわけなんですよね。 誤解がないところまですり合わせが出来た上で結論が変わらなければ、人それぞれなんだなという結論に達するのみです。


    私は純粋に知りたい思いますし、自分が常識外れであれば直したいと思うだけなんです。私も同じことをくどくど何度も言っていると思います。すみません。

     

     じゃんぬねっと さんからの引用

    ここ 2, 3 回のやりとりで思ったのですが、どうも前提のすり合わせが出来ていないように思います。 私の発言内容は特に断りがない場合は、発端となった trapemiya さんの発言が前提となっているとお考えください。 毎回前提をくどくど書いていると今以上に長文になるので、言わずもがなと思われる部分については前提を省略しています。 今回は誤解を説明するために新たな誤解を招いてはいけないと思い、必要以上に回りくどい説明をしたため重複した説明が多くなり長文になりましたが、たぶんこれで疑問は晴れると思います。 私の疑問については答えてくださっていないところがありますが (例示して欲しい件) 具体例をあげるのが難しいということは、私のスタイルで問題になることは滅多にないと考えることができるので、この点は満足です。


    確かに前提から私が飛躍してしまったようで、必要以上にこんがらがったようです。しかし、だいぶ晴れてきたと思います。発端となった私の発言に戻れば、イベントがベストなソリューションであろうと書いた通り、イベントを使うことに反対でもなければイベントを優先して考えることもあります。しかし、Form1とForm2が今後どのような関係になっていくのかわからず、場合によってはForm2がForm1のインスタンスを持つことが考えられるという私のスタンスはやはり変わっていません。くどいですが、インスタンスを持つこと自体はやはりそれほど悪いこととは今のところ思えません。独立性や一方性はイベントよりもインタフェースを用いれば確かに劣りますが、私はむしろそれを求めているように気づきました。インスタンスという言葉を出さずに、インターフェースという言葉を先に出した方が良かったかもしれません。これに関しては変な誤解を与えてしまったかもしれません。ごめんなさい。
    インスタンスを強い型で持つことは私も反対です。Form2にForm1の型が存在することは私の中でもあり得ません。

     

     じゃんぬねっと さんからの引用

    ちなみに飲酒しながらの投稿となりますので、日本語でおkなところがあったらお許しください。 酒が入っているわりにはまだまともに書いている方だと (酔っ払っている今は) 自画自賛しています。 酔いが冷めた時には後悔しているかもしれません。


    いえ、おっしゃる通りすばらしい文章でした。

    2008年11月24日 5:06
    モデレータ
  •  まどか さんからの引用

    なので、form2のコードにform1という型を記述することはまずありません。


    実は私の中で質問者のしげちゃん(さん)がform1の型をform2の中に書いた時点で、汎用性がなくなるのでインターフェースを使いましょうねというプランをぼんやり描いていたので、私が誤解を与えたのかもしれません。書き方が悪かったですね。すみません。

    私もform2にform1の型を記述することはまずありえません。

     

     まどか さんからの引用

    見解の違いは、私とじゃんぬさんはクラスを閉じようとするのを第一としますが

    trapemiya さんはあるものは活用しようという、第一ポリシーの違いなのでしょう。


    この発言にハッとしました。その通りですね。私もあるものは何でも無秩序に利用しようというわけではないですが、概ね第一ポリシーの違いじゃないかと私も思います。私はじゃんぬさんの発言でも書きましたが、インスタンスを合体させるようなイメージも持っています。これが正しいのか正しくないのかという結論は私の中では出ていませんが、みなさんは独立性や安全性を考えてとにかくクラス単位で閉じようとされているわけなんですよね。そこが私とどうやら差があるようです。

    例えばコンピュータというインスタンスがあり、そこにUSBやS-ATAというインターフェースで他のデバイスがつながってお互いにデータをやり取りするところまでは私の中ではOKですし、つながる時に制約も持たせたいのです。だから、コンピュータと他のデバイスをそれぞれ完全に独立させようとは思いませんし、あくまで、USBやS-ATAという縛られた制約のなかでつなげようとします。

    もちろん、このコンピュータとデバイスというグループと、例えばシャープペンと芯のグループとは通常は全く関係がないため、例えコンピュータとシャープペンを何かの拍子で一緒に使わなければならなくなった時は、独立性を第一に考えて新しいインターフェースなど導入せず、イベントでやり取りする方法をたぶん選ぶと思います。

     

    逆に言えば、イベントを使うと汎用性が高まりすぎる部分、つまり型でいえば弱い型の結合になるところが私としては嫌なんじゃないかと思いました。

    しかし、この辺り難しいところで、ここまでやるかってことはあります。ここはまどかさんと同じように揺れるところであって、"私もform2にform1の型を記述することはまずありえません。"と書きましたけど、明らかにform2ではform1以外の型を取らない確率が高い場合には、form2にform1の型を書く場合もあります。理想と工数削減は必ずしも一致しないので、これはこれで仕方のないことでしょう。これを言い出すと終わっちゃうのですがw

     

    いずれにしてもうまく頭の中で整理できていなかったようでみなさんを混乱させて申し訳ないのですが、書き進めていくうちにすこしずつ整理ができてきたように思います。

    2008年11月24日 5:36
    モデレータ
  •  trapemiya さんからの引用
    Form1が来ようが新しいForm3が来ようが、Form2のソースに変更が一切ないというのはイベントど同様です。

     

    コードの変更云々については、Interface の場合は概ね同意です。 これらは当初 trapemiya さんが言わんとしていたことを理解していなかったため出てしまった話です。 以後のコード変更うんぬんのお話も省略させて頂きます。

     

     trapemiya さんからの引用
    焦点となるのは、参照をForm2の中に持つか持たないかということになるように感じました。

     

    はい、そのあたりに関しては私とまどかさんの意見が一致しているところです。 ただ概念上の違いしか思い浮かばず、主観が絡むので言葉で説明して論ぜよというのは難しいです。

     

     trapemiya さんからの引用
    "無駄な参照はない方が安全です。 ただ、ここに関してはそれほど重要でないような気はします。"と言われていますが、無駄な参照は確かに要りませんが、インターフェースを使用する以上、いや、その概念から言って必要なので、無駄だとは感じていません。

     

    Interface で定義されているメンバだけで考えればそうですね。 "無駄" と書いたのは 入れ物 (Interface) ではなく実際に入っているインスタンスは Form1 の参照のことです。 そして "それほど重要でない" と書いたのは Interface から Form1 という厳密な型のインスタンスを取り出すコードをかける人が、直接 Form1 インスタンスに何か変更を加えるようなコードは書かないだろうという考えからです。 ただなるべくならとにかく安全策を取りたいというだけで、そこまで強い理由にはならないでしょう。

     

     trapemiya さんからの引用
    私はイベントで完全に独立させてしまうよりも、関連あるオブジェクトのグループはインターフェースで縛りたい方です。また、感覚的にはイベントで完全に独立したインスタンス同士が通信のみで協力して仕事をし合うのではなく、インターフェースで繋がり、一つのオブジェクトのように機能することもイメージします。例えば、合体ロボであったり、掃除機の先のアタッチメントであったりするようにです。

     

    その考えで実装する時は GUI ベースのものは複合コントロールや拡張コントロールで考えることが多いです。 ただ今回の例のような Form1 と Form2 のように Form として分かれている場合でかつ、呼び出し元と呼び出し先が明らかな場合は、やはり (独立というよりは) Form2 は 「呼び出し元」 の情報を知らない状態にさせようと考えます。 もし Form1 と Form2 が別の Form0 から呼び出され連携が必要であれば、trapemiya さんのような考えの方が良い場合もあるかもしれませんが、やはりその場合でも Form0 を介するように組めないかをまず考えると思います。


     trapemiya さんからの引用
    たぶん、そのインターフェース型を記述するのも嫌だということだと想像するのですが、イベントにしても独自のイベントなら記述しなければならないわけで、そこは同じですが、インターフェースだとその先のメソッド名やプロパティ名まで書かなきゃいけないところで独立性が無くなるということなのでしょうか?

     

    ここの説明は難しいですね。 ここの説明は、今回の投稿の最後に書かれた前提を解いてからの方が良いと考えますが、文字を小さくした状態で書いておきます (省略させて頂いても良かったのですが、せっかく書いたので残したいだけです)。

     

    Interface の型はどんなメンバ (メソッド・プロパティ) を持っているべきかという情報を持ちます。 trapemiya さんの手法だとこれを利用して然るべきタイミングでメンバを呼び出し、引数を用いて必要なデータを渡します。 私の手法だとイベントはイベント名しか持っておらず、イベント引数を用いて必要なデータを渡します。 イベントにしてもメソッドにしてもタイミングは Form2 の実装で決まります。 イベントの場合はそれを捕捉する相手が不在であっても何人いても問題ないというだけです。  『違いはこれだけじゃないか、独立性とは関係がないよね?』 と言うことを trapemiya さんは仰っているのだと思います。

     

    (ここも説明が難しくうまく伝えられないかもしれません) 違いがあるとすれば、先ほど trapemiya さんが書かれた 『独自のイベント引数を実装する場合は、独自の EventArgs の型を持つことになるじゃないか』 の部分に関してがあげられます。 ここでは独自のイベント引数の型と Interface の型とで比べてみます。 独自のイベント引数の型は Interface ほど実装に依存した型ではありません。 なぜなら独自のイベント引数が持つ通知したい情報というのは、trapemiya さんがメソッドを呼び出して引数に指定する情報と同じになるからです。 であるのに型は Interface ほど抽象的ではありません。 Interface の場合は呼び出し元のインスタンスを含めなければならず、そのために呼び出し元にインターフェイスを実装するという手間が発生します。 また Interface にはメンバという実装依存の情報を型に持つ必要があります。 渡そうとしている情報は同じであるのにインスタンスを利用しないと渡せないという違いもあります。

     

    一番大きいのは呼び出し元で呼び出し先をメソッドで呼び出すことによって、強く呼び出し元を意識することにより 「一方向ではなくなる」 という点で、まどかさんとも意見が一致しているところです。 しかし、一番大きいとは言うものの、概念上の違いしか思い浮かばず、「わかりやすい」 という理由にしても主観が絡むので言葉で説明して論ぜよというのは難しいです。 trapemiya さんにはこれが 「呼び出し元を意識する方がわかりやすいこともある」 と言っているので、やはり主観やセンスの違いでしかないのかなと思います (つまり正しいとか正しくないとか存在しないわけです)。

     

    個人的にはイベントは命名も楽だという理由もあります。 イベントの場合はイベント名が必要ですがイベント名はタイミングだけの命名となります。 Interface の場合は 「何をどうするか」 という命名をしないと、イベントと違ってターゲットのインスタンスを持つので不適切になり、案外悩みどころになることが多いです。 私がコーディングしていて最も時間がかかるのは命名です。orz

     

     trapemiya さんからの引用
    ここについては了解です。確かに言われているように.NETでは型が主役ですので、私もあまり弱い型にしたくありません

     

    でもインターフェイスを使わないといけない場合もあるわけですよね。 私はオブジェクト指向で好きなのは 「マルチプル インスタンス」 であって、「ポリモーフィズム」 とか 「継承」 はあまり使わないようにしています。 特に 「ポリモーフィズム」 はメリットもありますが、型がまがりなりにも弱くなるというデメリットもあると私は考えています (foreach のような列挙で使うことはありますが、これはデメリットが少ないため)。

     

     trapemiya さんからの引用
    ごめんなさい。ここは説明をすっとばしました。依存元が不定である以上、System.EventArgs の派生クラスをどのように作っていいのかがわからないというのが言いたかったのです。しかし、System.EventArgs の派生クラスでobject型を返すようになっていればその派生クラスは汎用的に使えるなというのが言いたかったんです。書き方も不適切だったかもしれません。

     

    今度は 「イベントを使う場合はイベント引数で情報を詰め込むしか方法がない」 と考えていなかったりしませんか? いや、これは私の説明がいつも極端だからいけないのかもしれません。

     

    依存元が不定である場合は中身が空っぽのイベントである System.EventHandler(object sender System.EventArgs e) を使うことになると思います。 つまりタイミングだけを知らせるわけですね。 データはどうやって取得するかですが、呼び出し元である Form1 は Form2 の存在を知っているわけですからタイミングさえ伝えておけば Form2 の参照からデータは取得できますよね。 単純にデータの連動だけであれば DataBinding と併用するのもありかもしれません。 この方法であれば、trapemiya さんが前回話していた (あまり仕様として遭遇することはないとは思いますが) 表示方法が変わるというような特殊な仕様にも対応できますよね。

     

     trapemiya さんからの引用
    これは私の前回謝った不適切な例に起因していると思います。イベントではできない場合を考えたつもりが、失敗しました。(^^;

     

    私も極端な例を用いたプロパガンダ的主張になってわかりにくい書き方をしている箇所があります。 このあたりはお互い様ということでお許しください。

     

     trapemiya さんからの引用
    例としては、Form2を閉じないままForm1にForm2の操作の結果を反映させたい場合です。例えば伝票入力Form1の画面があり、その画面を閉じないまま連続でデータを入力します。Form1では半リアルタイムで一覧が更新され、最大伝票番号なども更新します。ここを何が何でもイベントや DataBinding で処理されようとしているように受け取りました。

     

    "何が何でも" と書かれてしまうと、そういう実装をした方が難しいのに無理矢理やっているように感じ取られてしまいかねませんが、私がこれまで経験した中では無理矢理やる必要はなく、ごく自然にイベントの通知機能だけで処理できました。 そしてこの方法は非常に安易で難しくもなくコード量もかなり少ないです。 コード量に関しては 「強い型 (Form1) のままで呼び出し元を直接参照する方法」 に比べればイベントの宣言で 1 行多くなる程度ですので、Interface になった場合とで比べて面倒ではありません。 確かに DataBinding に関しては単純な仕様でないと使えないので使いどころは難しいです。

     

     trapemiya さんからの引用
    私はインスタンス経由でもいいんじゃない?と思っていましたので、その理由が知りたくてここまで長い話にさせてしまっているのです。今はポリシーの違いかな?と思い始めています。trapemiyaはインスタンスで処理しようとしているとんでもない奴だと思われるかもしれませんが、今のところ私にはそれほどいけないことだとは思えないのです。form2でインスタンスを持つことがそれほどいけないことだとは思えないのです。

     

    「絶対にいけない」 ほど強い主張をするつもりはなくて、2 ポストほど前に書かせて頂いたように、こちらの方がわかりやすいと思うのだけどなぁ、というのが発端です。

     

    状況によっては呼び出し先が呼び出し元の都合を考えることは何も悪いことではないと思います。

     

    その "状況" というのを具体例として出して頂けないでしょうか? これに関してはどうしても前提を整理しないと私の方では 「そうですね」 とも 「違うでしょう」 とも回答できないので...

     

     trapemiya さんからの引用
    呼び出し元と呼び出し先が完全に独立していることをじゃんぬさんやまどかさんは好まれるようですが、私はそうでもありません。同じグループというか、おなじ範囲でオブジェクト同士が仕事をするのであれば、そこまでの独立性は求めません。むしろ同じグループなんだから協力し合って働くのが効率的だと考えますし、グループ内に制約を導入したくも思います。

     

    先ほどから "独立" という言葉が散見されますが、独立ではなく 「呼び出し元から一方的な支配 (一方向性)」 というのが私とまどかさんが主張していることです。 独立という言葉を用いて良さそうなのは、Form2 から見た情報伝達方法のお話であります。 今ちょっと検索してみましたが "独立" という言葉を使っているのは trapemiya さんだけで、私やまどかさんの書き込みには存在しないですね。

     

     trapemiya さんからの引用
    その通りですし、そこは理解しているつもりです。私も書き進めながら気づいたのですが、例えばDataGridViewを書き換えるメソッド名は統一しようとか、そういう方に頭が行っているようです。だから普段は自然とイベントよりもインターフェースを多用するのかもしれません。極端な話、trapemiyaインタフェースを誰もが実装せよと王様気分なのかもしれません。もちろん、私一人の中ですよw

     

    つまり trapemiya さんは、私やまどかさんが最優先するのとは違う別の何か (たとえばメソッド名の統一) を最優先しているということで、私が言わんとしていることがわからないわけではないということでしょうか? メソッド名の統一についてですが、これはイベントを捕捉することになる側で統一すればいいだけではないのでしょうか?

     

     trapemiya さんからの引用
    インスタンスを強い型で持つことは私も反対です。Form2にForm1の型が存在することは私の中でもあり得ません。
     trapemiya さんからの引用
    ここについては了解です。確かに言われているように.NETでは型が主役ですので、私もあまり弱い型にしたくありません。
     trapemiya さんからの引用
    私もform2にform1の型を記述することはまずありえません

     

    これだと 「矛盾している」 とか突っ込まれかねませんよw

     

    ちなみに私は 「強い型をなるべく使いたい」 「『弱い型を使うしかここは抜け道がないなぁ』 という場面に出くわすこと自体が嫌い」 という理由があって、呼び出し先に呼び出し元の情報を持つのが嫌いなのだと思います (おお、これはわかりやすい説明だ)。 この考え方についてはどう思われますか?

     

     trapemiya さんからの引用
    いえ、おっしゃる通りすばらしい文章でした。

     

    読み取れる trapemiya さんがすばらしいです。 酔っていたこともあって前回重大なことを書き忘れていました。 今回の投稿では忘れないように書かせて頂いているので引用します。

     

     じゃんぬねっと さんからの引用
    依存元が不定である場合は中身が空っぽのイベントである System.EventHandler(object sender System.EventArgs e) を使うことになると思います。 つまりタイミングだけを知らせるわけですね。 データはどうやって取得するかですが、呼び出し元である Form1 は Form2 の存在を知っているわけですからタイミングさえ伝えておけば Form2 の参照からデータは取得できますよね。

     

    この方法であれば独自のイベント引数の型さえも不要です。 つまり規定の .NET Framework (BCL) の機能だけ (System.EventHander、System.EventArgs) を使ってタイミングだけ通知することになるのでまったく依存が生まれないです。 前回の投稿以前に 「これで不足する状況を実例としてあげてください」 というお願いをしていましたが、上記のような場合で考えて何か思いつく状況というのはありますでしょうか? 私にはそれが思い浮かばないのです。

     

    今回の投稿に 「独自のイベント引数型を使った場合の比較」 を頑張って書いてみましたが、上記の状況が浮かばないならこの部分の説明は不要だったかもしれません (でもイベント引数の話を最初に持ち出したのは私だったりする... orz)。

    2008年11月24日 10:04
  • #変な書き方なので訂正です。

     

     まどか さんからの引用

    インターフェースについても、今回の場合では考えません。

    form1 と form2 がお互いに依存していない場合において考えます。(純粋な第三者)

     

    インターフェースは人間で言えば名刺にあたると思います。

    つまり、今回の場合、form2 クラスの設計の話になり(form1から見ればform2と同様の既知の型)

    form2 を知っているform1 にとってはNewするのがform2型なのかインターフェース型なのかという単なるスタンスで

    したがって、form1がFormClosingを検知するか、form2がインターフェースにカスタムイベントを実装する方法を選択します。

    当然、目的のためにform2にインターフェースを新しく作るのはありかも知れませんが

    今回の場合で言うと、想定外の仕様が出てきたというのに等しい場面だと思います。

     

     じゃんぬねっと さんからの引用

    独立という言葉を用いて良さそうなのは、Form2 から見た情報伝達方法のお話であります。 今ちょっと検索してみましたが "独立" という言葉を使っているのは trapemiya さんだけで、私やまどかさんの書き込みには存在しないですね。

     

    依存(参照)の一方通行を満たせば各クラスが閉じられたものになります。

    そういう意味で独立という言葉を使われたと思うので他意はないと思います。

     

    2008年11月24日 16:00
  •  じゃんぬねっと さんからの引用

     trapemiya さんからの引用
    焦点となるのは、参照をForm2の中に持つか持たないかということになるように感じました。
     

     


    はい、そのあたりに関しては私とまどかさんの意見が一致しているところです。 ただ概念上の違いしか思い浮かばず、主観が絡むので言葉で説明して論ぜよというのは難しいです。


    これに関してはまどかさんは「依存関係の一方通行化はまず守るべきではと思っています。」と述べられていますし、じゃんぬさんも「一方向性」という言葉を出していらっしゃいます。確かにインターフェースの場合はお互いに参照しているため、参照の一方向性は崩れますが、イベントにしてもインターフェースにしても「実行してね。お願い」と頼まれたメソッドをひたすら実行するだけであり、その部分は全く同じであり、この限りではインスタンスを持つことが即、実行主体の一方向性が崩れることにはならないと思っています。なので、私は、インスタンス(インターフェース型に限ります)を持つことが具体的にどのような弊害があるのかを見つけられずいます。


     じゃんぬねっと さんからの引用

     Interface で定義されているメンバだけで考えればそうですね。 "無駄" と書いたのは 入れ物 (Interface) ではなく実際に入っているインスタンスは Form1 の参照のことです。 そして "それほど重要でない" と書いたのは Interface から Form1 という厳密な型のインスタンスを取り出すコードをかける人が、直接 Form1 インスタンスに何か変更を加えるようなコードは書かないだろうという考えからです。 ただなるべくならとにかく安全策を取りたいというだけで、そこまで強い理由にはならないでしょう。


    その通りですね。そのようなコードを書くことはありえないでしょう。

     

     じゃんぬねっと さんからの引用

    その考えで実装する時は GUI ベースのものは複合コントロールや拡張コントロールで考えることが多いです。 ただ今回の例のような Form1 と Form2 のように Form として分かれている場合でかつ、呼び出し元と呼び出し先が明らかな場合は、やはり (独立というよりは) Form2 は 「呼び出し元」 の情報を知らない状態にさせようと考えます。 もし Form1 と Form2 が別の Form0 から呼び出され連携が必要であれば、trapemiya さんのような考えの方が良い場合もあるかもしれませんが、やはりその場合でも Form0 を介するように組めないかをまず考えると思います。


     

    これについては後述のちょっとしたまとめを参照して下さい。

     

     じゃんぬねっと さんからの引用

    ここの説明は難しいですね。 ここの説明は、今回の投稿の最後に書かれた前提を解いてからの方が良いと考えますが、文字を小さくした状態で書いておきます (省略させて頂いても良かったのですが、せっかく書いたので残したいだけです)。

    小さい字の部分、一方向性を除いて、その通りだと思います。そんなに強く呼び出し元を意識しているわけではなく、Form2においてイベントのデリゲートを実行するのと、Form2においてインターフェースメソッドを実行するのは全く同じレベルだと思うのです。これはまどかさんの回答にも以前同じようなことを書きましたが、どちらもそれぞれの参照を辿ってメソッドを実行するだけですよね。インターフェースメソッドの方はForm1の参照が必要であるという点では呼び出し元を意識していますが、強くとまでは言えないんじゃないかと思います。なぜならどのような型の参照でもインターフェースさえ実装していれば受け取れるからです。

     

     じゃんぬねっと さんからの引用

    でもインターフェイスを使わないといけない場合もあるわけですよね。 私はオブジェクト指向で好きなのは 「マルチプル インスタンス」 であって、「ポリモーフィズム」 とか 「継承」 はあまり使わないようにしています。 特に 「ポリモーフィズム」 はメリットもありますが、型がまがりなりにも弱くなるというデメリットもあると私は考えています (foreach のような列挙で使うことはありますが、これはデメリットが少ないため)。


    全く同感です。私の組むアプリケーションのレベルでは、継承やポリモーフィズムを意識してクラスを設計することは多くありません。

     

     じゃんぬねっと さんからの引用

    今度は 「イベントを使う場合はイベント引数で情報を詰め込むしか方法がない」 と考えていなかったりしませんか? いや、これは私の説明がいつも極端だからいけないのかもしれません。

    が~ん。ノーマークでした。忘れてました。参りました。イベント引数のことばかり考えていました。
    ついでに言うと私の前回の発言におけるobject型うんぬんですが、これもよく考えるとあまり良い方法ではありません。最初はデリゲートやラムダ式を与えてイベント引数にセットする中身を変えればいいやぐらいに考えていたのですが、こんなことをForm1からForm2に対して行うぐらいなら、イベントハンドラでその中身を読み変えてしまえばいいわけですね。いや、こんなことを考えたのは呼び出し元が要求する値を、厳密な型で欲しかったのです。いずれにしてもおかしな話だったので忘れて下さい。ごめんなさい。

     

     じゃんぬねっと さんからの引用

    "何が何でも" と書かれてしまうと、そういう実装をした方が難しいのに無理矢理やっているように感じ取られてしまいかねませんが、私がこれまで経験した中では無理矢理やる必要はなく、ごく自然にイベントの通知機能だけで処理できました。 そしてこの方法は非常に安易で難しくもなくコード量もかなり少ないです。 コード量に関しては 「強い型 (Form1) のままで呼び出し元を直接参照する方法」 に比べればイベントの宣言で 1 行多くなる程度ですので、Interface になった場合とで比べて面倒ではありません。 確かに DataBinding に関しては単純な仕様でないと使えないので使いどころは難しいです。

     じゃんぬねっと さんからの引用

    「絶対にいけない」 ほど強い主張をするつもりはなくて、2 ポストほど前に書かせて頂いたように、こちらの方がわかりやすいと思うのだけどなぁ、というのが発端です。

    これらについても後述のちょっとしたまとめを参照して下さい。

     

     じゃんぬねっと さんからの引用

    状況によっては呼び出し先が呼び出し元の都合を考えることは何も悪いことではないと思います。
     


     

    その "状況" というのを具体例として出して頂けないでしょうか? これに関してはどうしても前提を整理しないと私の方では 「そうですね」 とも 「違うでしょう」 とも回答できないので...


    例えば、呼び出し先が呼び出し元の計算結果を受け取って処理を継続するような場合など、呼び出し元の処理の結果を気にする場合を考えていました。

     

     じゃんぬねっと さんからの引用

    先ほどから "独立" という言葉が散見されますが、独立ではなく 「呼び出し元から一方的な支配 (一方向性)」 というのが私とまどかさんが主張していることです。 独立という言葉を用いて良さそうなのは、Form2 から見た情報伝達方法のお話であります。 今ちょっと検索してみましたが "独立" という言葉を使っているのは trapemiya さんだけで、私やまどかさんの書き込みには存在しないですね。


    独立というのは、.NETに標準で用意されている以外の厳密な型を内部に持たないという意味で使っています。支配というより純粋にコード上でのお話です。他の特定のクラスとコード的に依存関係がないという意味です。わかりにくくてごめんなさい。

     

     じゃんぬねっと さんからの引用

    つまり trapemiya さんは、私やまどかさんが最優先するのとは違う別の何か (たとえばメソッド名の統一) を最優先しているということで、私が言わんとしていることがわからないわけではないということでしょうか? メソッド名の統一についてですが、これはイベントを捕捉することになる側で統一すればいいだけではないのでしょうか?


    メソッド名はインターフェースを使えば強制的に統一できますが、これは結果であって、インターフェースの目的ではないと思いますし、私はこれが重要だとは考えていません。(世の中の本では、メソッド名が統一されることを必要以上に強調されているような印象を受けますが・・・)
    最優先というわけでもないのですが、オブジェクトのグループを考える時です。概念的かもしれません。例えばUSBメモリを作る時、それはtrapemiyaのパソコン専用に作るのではなく、USBというインターフェース用に作るということです。そのUSBメモリがUSBインターフェースを持たないオブジェクトのことまでは考えません。USBインターフェースを通してオブジェクト同士は互いに連携することを考えるので、お互いを参照し合うことに特に違和感を感じません。何て言うのか、パーシャルクラスのオブジェクト版というか・・・。
    ちょっとうまく整理できていませんし、考察も十分に今までしてこなかったので(オイ)、自信を持って言えないのがなんとも・・・orz 裏を返せば、それで必死になってイベントに拘る理由を聞いているのかも?と気づきました。

     

     じゃんぬねっと さんからの引用

     trapemiya さんからの引用
    インスタンスを強い型で持つことは私も反対です。Form2にForm1の型が存在することは私の中でもあり得ません。
     

     trapemiya さんからの引用
    ここについては了解です。確かに言われているように.NETでは型が主役ですので、私もあまり弱い型にしたくありません。
     

     trapemiya さんからの引用
    私もform2にform1の型を記述することはまずありえません
     

    これだと 「矛盾している」 とか突っ込まれかねませんよw


    状況が違いますよ。いじわるw 最初と最後はインターフェース型のことを言っていますし、真ん中は説明するまでもないでしょうw

     

     じゃんぬねっと さんからの引用

    ちなみに私は 「強い型をなるべく使いたい」 「『弱い型を使うしかここは抜け道がないなぁ』 という場面に出くわすこと自体が嫌い」 という理由があって、呼び出し先に呼び出し元の情報を持つのが嫌いなのだと思います (おお、これはわかりやすい説明だ)。 この考え方についてはどう思われますか?


    私もそうです。インタフェースはインタフェース型で捉えれば強い型かもしれませんが、いかなる型でも受け入れられるということであれば弱い型になるので、インターフェース型を内部に持つことは全然OKです。といいますか、.NETの標準のクラスにはこういう例はたくさんあります。

     

     じゃんぬねっと さんからの引用

    この方法であれば独自のイベント引数の型さえも不要です。 つまり規定の .NET Framework (BCL) の機能だけ (System.EventHander、System.EventArgs) を使ってタイミングだけ通知することになるのでまったく依存が生まれないです。 前回の投稿以前に 「これで不足する状況を実例としてあげてください」 というお願いをしていましたが、上記のような場合で考えて何か思いつく状況というのはありますでしょうか? 私にはそれが思い浮かばないのです。


    ありません。無いでしょう。先にも書きましたが、これは全く頭にありませんでした。一方向性というのを、Form2からForm1への通知のみと勝手に勘違いしていたようです。


    さて、これまでのことをちょっとまとめてみます。

     

    イベントはデリゲート型を通してメソッドが結びつく。インターフェースはインターフェース型を通してインスタンスが結びつく。インスタンスにはメソッドが含まれるので、やれることはイベントもインターフェースも同じである。基本的にやれることが同じであれば独立性が高く、かつ、一方向で支配できるイベントでいいじゃないか、困ることないし。余計なインスタンス持ちたくないし。というのがじゃんぬさんやまどかさんの意見だと思います。
    私はこの意見について全くありだと思いますし、間違っていないと思います。ただ、私はその独立性や一方向性をある程度犠牲にしてでも(注1)、いや、むしろ完全に独立ではなくグループとして動作を考えたい場合は、インターフェースの採用を検討します。
    また、これは書き進めているうちに気が付いたのですが、呼び出し先が呼び出し元の実行結果を期待する場合はインターフェースが便利ではないか?(ちょっと眠いので頭が回らない・・・)

     

    というわけで、基本的にはポリシーの違いでしかないのかな・・・。とカッコいいことを書いていますが、単に私がインタフェースに書き慣れているだけかもしれません。じゃんぬさんがイベントで困らないように、私もインターフェースで困ったことが無いのです。じゃんぬさんもちいさい字のところで比較されていましたが、一番大きいのは一方向性だと言われていました。これに関しては最初のころからずっと申し上げているように、インターフェースも違いはないと思うのです。理由は以下にも書きました。


    (注1)
    インスタンスを持つことが、イコール、独立性や一方向性を否定するものではない。インターフェース型はいかなる型でも受け入れ可能という意味でそれなりに独立しているし、一方向性については、イベントを発火してデリゲートを実行するかインスタンスメソッドを実行するかの違いであり、この限りではどちらも同じである。というか、Form2がForm1のメソッドを実行するし、Form1もForm2のメソッドを実行するし、この時点で一方向性というのは何を意味するのであろうか? Form1でしかコーディングしないということなのであろうか? それであったとしてもインターフェースメソッドも満たしている。

    2008年11月24日 16:39
    モデレータ
  •  まどか さんからの引用
    依存(参照)の一方通行を満たせば各クラスが閉じられたものになります。

    そういう意味で独立という言葉を使われたと思うので他意はないと思います。

     

    あ、これは意地悪で書いたわけではなくて、「独立」 というと誰にも関与されずに自立しているような表現に見えたので違和感があったのです。 国の独立とかをイメージすると今回はむしろ 「独立」 ではなく 「支配」 の方が御幣はないかなぁと思ったのです。 他意があると考えていたわけではありませんし、もちろん私自身にも他意はないですよ。 意地悪で書いているところは trapemiya さん自身も意地悪だと気づけるように書いています。 まあ、こんなことは trapemiya さん相手でないとできない気はしますw

    2008年11月24日 16:50
  •  まどか さんからの引用

    #変な書き方なので訂正です。

     

     まどか さんからの引用

    インターフェースについても、今回の場合では考えません。

    form1 と form2 がお互いに依存していない場合において考えます。(純粋な第三者)

     

    インターフェースは人間で言えば名刺にあたると思います。

    つまり、今回の場合、form2 クラスの設計の話になり(form1から見ればform2と同様の既知の型)

    form2 を知っているform1 にとってはNewするのがform2型なのかインターフェース型なのかという単なるスタンスで

    したがって、form1がFormClosingを検知するか、form2がインターフェースにカスタムイベントを実装する方法を選択します。

    当然、目的のためにform2にインターフェースを新しく作るのはありかも知れませんが

    今回の場合で言うと、想定外の仕様が出てきたというのに等しい場面だと思います。

     

    このまどかさんの引用元の文章はもう無いのでしょうか? そこだけの引用だとごめんなさい、よくわかりません・・・・

    インターフェース無しの前提は私の中ではありえないのです。イベントを使わないという意味ではありません。

     

    form1でNewするのはform2です。インターフェース型でNewしても良いんですが、大した差はありません。どのみちForm2のインターフェース型変数にその参照を渡してしまうのが理由です。

     

    "form2がインターフェースにカスタムイベントを実装する方法を選択します。"は、引用されたインターフェースについては今回は考えませんと矛盾するのですが、ということは引用を否定された訂正ということなのでしょうか?

     

    また、名刺にあたる理由ももう少し詳しくお願いできませんでしょうか?

     

    #すみません、夜更けなので少し思考が落ちてます・・・

     

     まどか さんからの引用

    依存(参照)の一方通行を満たせば各クラスが閉じられたものになります。

    そういう意味で独立という言葉を使われたと思うので他意はないと思います。

     

    クラスが閉じるというのは、そのクラスが他のクラスのメンバーを一切扱わない状態ということでよろしいのでしょうか?

    イベントは参照を渡さずにForm1のメソッドを実行しますが、インタフェースメソッドは参照を利用してForm1のメソッドを実行します。どちらもForm2がForm1のメソッドを実行することに変わりがないことは以前にも書きましたが、これについはどうお考えなのでしょうか?

    私、何か意味を取り違えているのかもしれませんが・・・

     

    また独立というのは、クラスの内部にインターフェース型を除いて、.NETに標準に存在しない厳密な型(例えばForm1)を持たないという意味で言っています。なので参照の一方通行、つまり参照を持たないという意味とは正確には異なります。でも、フォローありがとうございます。

    2008年11月24日 17:22
    モデレータ
  • 具体的に書くと

     

    Code Snippet

    Public Interface IForm1
        Sub CloseEx()
    End Interface
    Public Class Form1
        Implements IForm1
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim f As New Form2(Me)
            f.Show()
        End Sub
        Public Sub Close1() Implements IForm1.Close
            Me.Close()
        End Sub
    End Class
    Public Class Form2
        Private _IForm1 As IForm1
        Public Sub New(ByVal f As IForm1)
            _IForm1 = f
        End Sub
        Private Sub Form2_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
            _IForm1.CloseEx()
        End Sub
    End Class

     

     

     

    この IForm1 を第三者ととらえるか否かなのかな。

    私としてはインスタンスを渡すのと等価と考えますねぇ。

    2008年11月24日 17:36
  •  まどか さんからの引用

    具体的に書くと

     

    Code Snippet

    Public Interface IForm1
        Sub CloseEx()
    End Interface
    Public Class Form1
        Implements IForm1
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Dim f As New Form2(Me)
            f.Show()
        End Sub
        Public Sub Close1() Implements IForm1.Close
            Me.Close()
        End Sub
    End Class
    Public Class Form2
        Private _IForm1 As IForm1
        Public Sub New(ByVal f As IForm1)
            _IForm1 = f
        End Sub
        Private Sub Form2_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
            _IForm1.CloseEx()
        End Sub
    End Class

     

     

    コードのイメージはそうですね。ただ、誤解の無いように念のために付け加えますが、決して、イベントじゃなくこのコードのように書けと言っていないのは何度も申している通りです。

     

     まどか さんからの引用

    この IForm1 を第三者ととらえるか否かなのかな。

    私としてはインスタンスを渡すのと等価と考えますねぇ。

     

    なぜ IForm1 を第三者と捉えられるのでしょうか? Form1でもForm2でも無いからでしょうか?

    IForm1 はForm1のインスタンスそのものです。インスタンスはForm1とForm2の2つしか存在しません。

    したがってForm1のインスタンスを渡しているのであり、「私としてはインスタンスを渡すのと等価と考えますねぇ。」は何と等価と考えられているのでしょうか? 「インスタンスを渡す」と等価だとすれば、対は「インスタンスを渡さない」ということですが、私がインスタンスを渡すことが問題になっていますのでこれは違いますし、「インスタンス」の部分が等価だとすれば他のインスタンスと比べていることになりますが、渡すのはForm1のインスタンスしかありえず、これも違う・・・

    2008年11月24日 17:51
    モデレータ
  •  trapemiya さんからの引用

    なぜ IForm1 を第三者と捉えられるのでしょうか? Form1でもForm2でも無いからでしょうか?

    IForm1 はForm1のインスタンスそのものです。インスタンスはForm1とForm2の2つしか存在しません。

    したがってForm1のインスタンスを渡しているのであり、「私としてはインスタンスを渡すのと等価と考えますねぇ。」は何と等価と考えられているのでしょうか? 「インスタンスを渡す」と等価だとすれば、対は「インスタンスを渡さない」ということですが、私がインスタンスを渡すことが問題になっていますのでこれは違いますし、「インスタンス」の部分が等価だとすれば他のインスタンスと比べていることになりますが、渡すのはForm1のインスタンスしかありえず、これも違う・・・

     

    まず今回の場合でインターフェースを使う方法がこれしか想像できませんでした。

    インスタンスはForm1ですが、インターフェースによる疎結合なり

    それがtrapemiyaさんの許容部分なのかなと思ったわけです。

    確かにコンパイルはインターフェースでおこなわれ、インスタンスの解決は実行時になりますね。

     

    #昨夜、別の人が投稿して三人に点数をつけている夢を。。。

    2008年11月25日 0:20
  •  まどか さんからの引用

    まず今回の場合でインターフェースを使う方法がこれしか想像できませんでした。

     

    さすがにまどかさん、びしっとズバリのコードを書いていただきました。本来は私が提示しなければなりませんでしたね。

     

     まどか さんからの引用

    インスタンスはForm1ですが、インターフェースによる疎結合なり

    それがtrapemiyaさんの許容部分なのかなと思ったわけです。

     

    先の私が言った「独立性」とはこのことなんです。疎結合ですか、良い表現なのでいただいちゃいますw

    イベントはデリゲート型で疎結合になり、インターフェースはインターフェース型で疎結合になるわけです。問題は、インスタンスを互いに参照し合うことが問題かどうかだと思っています。私は今のところ問題はないと考えています。あとでまとめますので、よろしければまた意見をお願いします。

     

     まどか さんからの引用

    #昨夜、別の人が投稿して三人に点数をつけている夢を。。。

     

    なので、本当にポリシーの違いだけじゃないかと今のところ思っています。

     

    #私は考えだしたら眠れなくなったので、寝不足です・・・orz

    2008年11月25日 0:49
    モデレータ
  • trapemiya さんとのディベートっぽいのはもう終わりになりそうですね。

     

     trapemiya さんからの引用
    確かにインターフェースの場合はお互いに参照しているため、参照の一方向性は崩れますが、イベントにしてもインターフェースにしても「実行してね。お願い」と頼まれたメソッドをひたすら実行するだけであり、その部分は全く同じであり、この限りではインスタンスを持つことが即、実行主体の一方向性が崩れることにはならないと思っています。

     

    あくまで Interface であり、呼び出し元 (Form1) 以外のインスタンスが入っていることも考えられますから、今回のような場合はたまたま呼び出し元である Form1 のインスタンスが入っていると考えれば良いのでしょうか?

     

     trapemiya さんからの引用
    なので、私は、インスタンス(インターフェース型に限ります)を持つことが具体的にどのような弊害があるのかを見つけられずいます。

     

    trapemiya さんに突きつけられそうな弊害はないのだと思います。 trapemiya さんを見ていると、もともと "弊害" とまで言えるレベルなどないのではないかとさえ思えてきます。 個人的には型が弱くなること (できれば強い方が良い)、実際のインスタンスは Interface ではなく Form1 であること、Interface を定義する方が実際には面倒くさいこと、親で 「渡す」 「取得する」 の一元化ができないこと、お相手が複数に及んだ場合は Form2 を少し修整しなければならないこと (イベントは受け取りたい人が受け取れば良いだけ)、別の案件へ流用しやすいこと。 などなどが挙げられますが、これらは trapemiya さんに申し上げた内容の総括にすぎません。

     

     trapemiya さんからの引用
    小さい字の部分、一方向性を除いて、その通りだと思います。

     

    小さい文字の部分は、むしろ一方向性の部分以外は理解不能なくらいグダグダだったと思ったのですが、読み取って頂けるとは嬉しいです。

     

     trapemiya さんからの引用
    そんなに強く呼び出し元を意識しているわけではなく、Form2においてイベントのデリゲートを実行するのと、Form2においてインターフェースメソッドを実行するのは全く同じレベルだと思うのです。これはまどかさんの回答にも以前同じようなことを書きましたが、どちらもそれぞれの参照を辿ってメソッドを実行するだけですよね。インターフェースメソッドの方はForm1の参照が必要であるという点では呼び出し元を意識していますが、強くとまでは言えないんじゃないかと思います。なぜならどのような型の参照でもインターフェースさえ実装していれば受け取れるからです。

     

    ここは考え方の違いなのだと思います。 私は Interface は弱い型と言いつつもインスタンスも入っていますし、イベントよりは強い存在なのだと思います。 一方イベントは Interface より存在がわかりにくいです。 呼び出し元でさえ把握できていれば良いので今回はイベントを使いました。 しかし今回のような主従関係がない場合はむしろ強い型で関連させて依存を明らかにした方が良いパターンもあるかもしれません (Form ではなかなか実例はないと思いますが)。 この場合は Interface より強い型を用いたいと考えますので、個人的にはこういった連携で Interface の出番がないのですね (他のパターンでは出番はあります)。

     

     trapemiya さんからの引用
    が~ん。ノーマークでした。忘れてました。参りました。イベント引数のことばかり考えていました。

     

    ですよね。 もともとイベント引数のお話が出たのは 『イベントでは表示方法の制御がある場合は対応できないのではないか?』 の対話の中です。 私は 『特殊な通知はイベント引数が望ましいかな』 と思い提示したのですが、これ以降、私と trapemiya さんの中でイベント プロシージャ内でフツーに取得するという考えがなぜか消えてしまったのですね。 決してわざと黙っていて trapemiya さんを誘い込んだわけではありませんぜw

     

     trapemiya さんからの引用
    ついでに言うと私の前回の発言におけるobject型うんぬんですが、これもよく考えるとあまり良い方法ではありません。最初はデリゲートやラムダ式を与えてイベント引数にセットする中身を変えればいいやぐらいに考えていたのですが、こんなことをForm1からForm2に対して行うぐらいなら、イベントハンドラでその中身を読み変えてしまえばいいわけですね。いや、こんなことを考えたのは呼び出し元が要求する値を、厳密な型で欲しかったのです。いずれにしてもおかしな話だったので忘れて下さい。ごめんなさい。

     

    なんなら trapemiya さんもこの日はお酒を飲んでいたということにしておきましょうよ。

     

     trapemiya さんからの引用
    例えば、呼び出し先が呼び出し元の計算結果を受け取って処理を継続するような場合など、呼び出し元の処理の結果を気にする場合を考えていました。

    この事例は、先にあった 『ノーマーク』 の部分で一網打尽にできそうですよね。

     

     trapemiya さんからの引用
    メソッド名はインターフェースを使えば強制的に統一できますが、これは結果であって、インターフェースの目的ではないと思いますし、私はこれが重要だとは考えていません。(世の中の本では、メソッド名が統一されることを必要以上に強調されているような印象を受けますが・・・)最優先というわけでもないのですが、オブジェクトのグループを考える時です。概念的かもしれません。

     

    であれば、ますます Interface である必要もないとも言えるのかなと思います。 Interface の場合は名前が異なっていても結果的に同じものをまとめることができるので、これを指しているのかなと思ったのですが。

     

     trapemiya さんからの引用
    状況が違いますよ。いじわるw 最初と最後はインターフェース型のことを言っていますし、真ん中は説明するまでもないでしょうw

     

    前置きがないと突っ込まれますよという意地悪で書いているんですw

     

     trapemiya さんからの引用
    ありません。無いでしょう。先にも書きましたが、これは全く頭にありませんでした。一方向性というのを、Form2からForm1への通知のみと勝手に勘違いしていたようです。

     

    ここで 「勝利のファンファーレ」 を脳内 BGM として演奏。

     

     trapemiya さんからの引用
    というか、Form2がForm1のメソッドを実行するし、Form1もForm2のメソッドを実行するし、この時点で一方向性というのは何を意味するのであろうか? Form1でしかコーディングしないということなのであろうか? それであったとしてもインターフェースメソッドも満たしている。

     

    イベントの場合は (Insider 的なお話は抜きにして) 参照を持っている側が監視した結果で得られた 「タイミング」 を捕捉しているから 「一方向性」 であると捉えています (通知しているというレベルで考えると同じだと言われてしまうんですが)。 逆に Interface の場合は参照へのメソッドの呼び出しが生じますから 「一方向性」 とは言い難いと考えます。 コーディング レベルで考えた場合の違いは、Interface の場合はメソッドによる外部への呼び出しが必要ですが、イベントの場合は自分自身のイベントの定義と、『はい、イベント起きた』 とそのタイミングを書くだけです。 つまりイベントの場合は、そのイベントを捕捉する側で (呼び出し元で) 参照を持っていれば良いという状態になります。 Interface の場合は型はどうであれインスタンスを双方で保持しなくてはならないという状態になります。 この 3 点 が一方向性におけるポイントかなと思います。 ただし trapemiya さんは、この考え方によって Interface の何が劣るのかわからないと仰るので、おそらく理由として弱い (あくまで私の主観的理由でしかない) のでしょう。

     

     trapemiya さんからの引用
    また、これは書き進めているうちに気が付いたのですが、呼び出し先が呼び出し元の実行結果を期待する場合はインターフェースが便利ではないか?(ちょっと眠いので頭が回らない・・・)

     

    呼び出し元が呼び出し先の情報をすべて受け取れると言えるので便利さ自体は変わらないと思います。 また思いついたら教えてください。

     

    あとはまどかさんとの第二ラウンドが待っています。

    2008年11月25日 1:36
  •  じゃんぬねっと さんからの引用

    あくまで Interface であり、呼び出し元 (Form1) 以外のインスタンスが入っていることも考えられますから、今回のような場合はたまたま呼び出し元である Form1 のインスタンスが入っていると考えれば良いのでしょうか?

     

    その通りです。


     じゃんぬねっと さんからの引用

     個人的には型が弱くなること (できれば強い方が良い)、実際のインスタンスは Interface ではなく Form1 であること、Interface を定義する方が実際には面倒くさいこと、親で 「渡す」 「取得する」 の一元化ができないこと、お相手が複数に及んだ場合は Form2 を少し修整しなければならないこと (イベントは受け取りたい人が受け取れば良いだけ)、別の案件へ流用しやすいこと。 などなどが挙げられますが、これらは trapemiya さんに申し上げた内容の総括にすぎません。

     

    >個人的には型が弱くなること (できれば強い方が良い)


    個人的には型が弱くなるとは言え、インターフェース型でのみでやり取りを行うので、そういう意味では厳密な型だと思います。弱いのに強いというか・・・。

     

    >実際のインスタンスは Interface ではなく Form1 であること

     

    これは弱い型が嫌というところから来ていると思いますが、私が嫌じゃないのはすぐ上の理由によります。

     

    >Interface を定義する方が実際には面倒くさいこと


    これも個人的にはそこまで面倒とは思いません。状況や主観による場合が多いと思います。まどかさんもイベントをたくさん作るのが面倒でインスタンスを渡すことがあるとおっしゃっています。でもまぁ、そこまでしてインタフェースを作らなくても・・・と感じるのは理解できます。

     

    >親で 「渡す」 「取得する」 の一元化ができないこと

     

    これも感覚的なことだと思うんです。イベントはデリゲート型を使用してそういう仕組みが最初から.NETに用意されていますが、インターフェースの場合はインタフェース型を利用してイベントと同じような仕組みを作っているだけです。同じようなと書いたのは、そこにデリゲート型とインターフェース型の違いある点と、相手のインスタンスを持つか持たないかの違いであり、一元化できるできないに違いはないと思うのです。インタフェースもイベントと同じように親でのみ「渡す」 「取得する」などを記述するだけで済みます。

     

    >お相手が複数に及んだ場合は Form2 を少し修整しなければならないこと (イベントは受け取りたい人が受け取れば良いだけ)


    これはイベントの特権というか主な目的ですので、この目的を考慮するのであればインタフェースの出番は最初からありません。

     

    >別の案件へ流用しやすいこと。

     

    これもたぶん慣れの問題だと思います。コードの保守性に関しては、両方とも疎結合であり、大きな差はないと思います。

     

    >これらは trapemiya さんに申し上げた内容の総括にすぎません。


    私もこれまでの統括という意味で改め上に書いてみました。

     

     じゃんぬねっと さんからの引用

    小さい文字の部分は、むしろ一方向性の部分以外は理解不能なくらいグダグダだったと思ったのですが、読み取って頂けるとは嬉しいです。

     

    実は私が今主に考えているのは一方向性の問題です。これは後述します。

     

     じゃんぬねっと さんからの引用

    ここは考え方の違いなのだと思います。 私は Interface は弱い型と言いつつもインスタンスも入っていますし、イベントよりは強い存在なのだと思います。

     

    > 私は Interface は弱い型と言いつつもインスタンスも入っていますし、イベントよりは強い存在なのだと思います。 一方イベントは Interface より存在がわかりにくいです。

     

    その通りだと思いますし、そこはじゃんぬさんと考え方に差はないと私は認識してます。私はこれまで述べた通り、これらの点は大きな問題でないと考えており、そうであればイベントもインたーフェースメソッドも仕組み的には同じであると言っても言い過ぎではないと思うのです。この点は考え方というか、どのような側面から両者を見ているのかによるのだと思います。私は技術的には両者は同じようなことをして疎結合を実現しているので、疎結合の側面から見れば同レベルだと考えています。一方で、イベントは通知してもらうもの、インターフェースメソッドは実行するものという側面で見れば異なったものとなるでしょう。しかし、インターフェースメソッドは実行するコードを確かに自分で書きますが、イベントはそれが最初から標準で用意されているというだけの差であり、自分でインターフェースメソッドを実行するコードを書いた後は、イベントと全く同様に動作すると言っても過言ではないと認識しています。

     

     じゃんぬねっと さんからの引用

     決してわざと黙っていて trapemiya さんを誘い込んだわけではありませんぜw

     

    わかってますし、例えそうであったとしても気付かない私がダメなんですから。

     

     じゃんぬねっと さんからの引用

    なんなら trapemiya さんもこの日はお酒を飲んでいたということにしておきましょうよ。

     

    あんがと。実際、ボジョレー飲んでたしw

     

     じゃんぬねっと さんからの引用

     trapemiya さんからの引用
    例えば、呼び出し先が呼び出し元の計算結果を受け取って処理を継続するような場合など、呼び出し元の処理の結果を気にする場合を考えていました。
     


    この事例は、先にあった 『ノーマーク』 の部分で一網打尽にできそうですよね。

     

    イベントを使った方法だとちょっと思い浮かびません。インタフェースメソッドであれば、呼び出し先で単純にその戻り値を受け取ればいいんですが、イベントの場合はどこのだれがどんなイベントハンドラを実行してるかわかりませんし、おまけにどんな型や値が呼び出し先に返ってくるか保障もないし、また呼び出し先に値が返ってくるとしても、どのタイミングでどのように受け取り、またそれはどのイベントハンドラが返したものかを知るのでしょうか?

     

     じゃんぬねっと さんからの引用

     trapemiya さんからの引用
    メソッド名はインターフェースを使えば強制的に統一できますが、これは結果であって、インターフェースの目的ではないと思いますし、私はこれが重要だとは考えていません。(世の中の本では、メソッド名が統一されることを必要以上に強調されているような印象を受けますが・・・)最優先というわけでもないのですが、オブジェクトのグループを考える時です。概念的かもしれません。
     

     


    であれば、ますます Interface である必要もないとも言えるのかなと思います。 Interface の場合は名前が異なっていても結果的に同じものをまとめることができるので、これを指しているのかなと思ったのですが。

     

    繰り返しになるかもしれませんが、インターフェースはメソッド名を統一するのが目的ではなく、クラス同士を接続するのが目的であり、そのための手段がメソッド名を統一することです。なので、メソッド名を統一することを考えてインターフェースを私は使っているわけではありません。メソッド名を揃えるということはインターフェースを使用する際の必要条件ですが、十分条件ではありません。

     

     じゃんぬねっと さんからの引用

    前置きがないと突っ込まれますよという意地悪で書いているんですw

     

    じゃんぬさんにはわかっていたじゃないw 掲示板だということを忘れてたw

     

     じゃんぬねっと さんからの引用

    ここで 「勝利のファンファーレ」 を脳内 BGM として演奏。

     

    orz

     

     じゃんぬねっと さんからの引用

    イベントの場合は (Insider 的なお話は抜きにして) 参照を持っている側が監視した結果で得られた 「タイミング」 を捕捉しているから 「一方向性」 であると捉えています (通知しているというレベルで考えると同じだと言われてしまうんですが)。 逆に Interface の場合は参照へのメソッドの呼び出しが生じますから 「一方向性」 とは言い難いと考えます。 コーディング レベルで考えた場合の違いは、Interface の場合はメソッドによる外部への呼び出しが必要ですが、イベントの場合は自分自身のイベントの定義と、『はい、イベント起きた』 とそのタイミングを書くだけです。 つまりイベントの場合は、そのイベントを捕捉する側で (呼び出し元で) 参照を持っていれば良いという状態になります。 Interface の場合は型はどうであれインスタンスを双方で保持しなくてはならないという状態になります。 この 3 点 が一方向性におけるポイントかなと思います。 ただし trapemiya さんは、この考え方によって Interface の何が劣るのかわからないと仰るので、おそらく理由として弱い (あくまで私の主観的理由でしかない) のでしょう。

     

    > (通知しているというレベルで考えると同じだと言われてしまうんですが)

     

    そこを言っているんです。イベントは通知してもらっているという印象が強いのですが、通知してもらっているわけではなく単にデリゲートを相手のタイミングで実行してもらっているだけです。この点についてはインターフェースメソッドとなんら変わりません。

     

    >逆に Interface の場合は参照へのメソッドの呼び出しが生じますから 「一方向性」 とは言い難いと考えます。

     

    これはインスタンスを参照しており、そのメソッドを実行しているから、つまり、そこからインスタンスをお互いに参照し合っていることを指しているのだと思うのですが、これを指しているのであれば、私はこれが問題であるとは考えていないのです。したがって、これが一方向性であるならば、何のために一方向性を守らなければならないのかがわからないのです。相手に関係なくコードを改修できるという回答が返ってきそうですが、これはインターフェースとて同じことです。"おそらく理由として弱い"と言われていますので、くどかったかもしれません。

     

     じゃんぬねっと さんからの引用

    呼び出し元が呼び出し先の情報をすべて受け取れると言えるので便利さ自体は変わらないと思います。 また思いついたら教えてください。

     

    これは上に書いたとおりです。

     

     じゃんぬねっと さんからの引用

    あとはまどかさんとの第二ラウンドが待っています。

     

    まどかさんとのやりとりとかぶってきたので、あらためてまとめを作成しているところです。あくまで私が勝手に考えていることなのですが、そう言わず、よかったらまた突っ込んでください。
    私の今の一番の関心ごとは一方向性です。

    2008年11月25日 4:05
    モデレータ
  • まとめ的な部分に関しては、trapemiya さんの応答で意思疎通ができていると思いますので割愛させて頂きます。 発端となった、こちらの元質問である回答については trapemiya さんもイベントの方が良いと仰っているので、それ以外の場合は臨機応変で場合によるとします。

     

     trapemiya さんからの引用
    これはイベントの特権というか主な目的ですので、この目的を考慮するのであればインタフェースの出番は最初からありません。

     

    そりゃそうですね。 これは反則前提でした。

     

     trapemiya さんからの引用
    その通りだと思いますし、そこはじゃんぬさんと考え方に差はないと私は認識してます。私はこれまで述べた通り、これらの点は大きな問題でないと考えており、そうであればイベントもインたーフェースメソッドも仕組み的には同じであると言っても言い過ぎではないと思うのです。この点は考え方というか、どのような側面から両者を見ているのかによるのだと思います。私は技術的には両者は同じようなことをして疎結合を実現しているので、疎結合の側面から見れば同レベルだと考えています。一方で、イベントは通知してもらうもの、インターフェースメソッドは実行するものという側面で見れば異なったものとなるでしょう。しかし、インターフェースメソッドは実行するコードを確かに自分で書きますが、イベントはそれが最初から標準で用意されているというだけの差であり、自分でインターフェースメソッドを実行するコードを書いた後は、イベントと全く同様に動作すると言っても過言ではないと認識しています。

     

    ここの捉え方が相違しているので当然結論が分かれてしまうわけですね。 私はイベントはインターフェイスよりもっと特化した部分で扱うという考え方です。 今回のような場合は 「実行するものを呼び出す」 より 「そのタイミングになったよと独り言を言う (捕捉したいヤツがその後勝手に何かしろ)」 が良いと考えています。 でないと全部インターフェイスで実装可能ですし、その理論でいくとまさに Java と変わらないということになります。 どういうことかと言うと、Java を専攻している方から 『プロパティはメソッドが特化したもので不要』 という意見を聞きますが、これと似たようなものだということです。 私が自作イベントを使っている目的の大半は 「データ (表示も含む) の更新」 ですが、これをインターフェイスで置き換えられると、もうイベントの出番がほとんど失せてしまいます (自作コントロールではそれなりに出番がありますが)。

     

     trapemiya さんからの引用
    イベントを使った方法だとちょっと思い浮かびません。インタフェースメソッドであれば、呼び出し先で単純にその戻り値を受け取ればいいんですが、イベントの場合はどこのだれがどんなイベントハンドラを実行してるかわかりませんし、おまけにどんな型や値が呼び出し先に返ってくるか保障もないし、また呼び出し先に値が返ってくるとしても、どのタイミングでどのように受け取り、またそれはどのイベントハンドラが返したものかを知るのでしょうか?

     

    イベントの基本は 「発火したらそれまで」 ですね。 今回の話題にあがった半リアルタイムの連動はデータが同じであるという前提で話を進めていたので、戻り値的なものは必要ないと考えていました。 戻り値を必要とする場合は、その時点で 2 つがかなり密接に関わっている (同位置で通信し合っている) と言えるので、もはや呼び出し元、呼び出し先という関係でない方が正しいような気がします。

     

    ここまで来ると仕様変更を考えるようになります。 どうしても仕様変更ができない場合はインターフェイスを使った方が良いです。 もちろんイベント + α でやってできないことはありませんが、この状況でイベントを使うのは私もイケてないと考えます。 この前提であれば trapemiya さんの勝利ですね。 Let's ファンファーレ。

     

    繰り返しになるかもしれませんが、インターフェースはメソッド名を統一するのが目的ではなく、クラス同士を接続するのが目的であり、そのための手段がメソッド名を統一することです。なので、メソッド名を統一することを考えてインターフェースを私は使っているわけではありません。メソッド名を揃えるということはインターフェースを使用する際の必要条件ですが、十分条件ではありません。

     

    だとすると、当初 trapemiya さんが話題に出した 「メソッド名を揃える」 というのは何を指しているのでしょうか?

     

     trapemiya さんからの引用
    そこを言っているんです。イベントは通知してもらっているという印象が強いのですが、通知してもらっているわけではなく単にデリゲートを相手のタイミングで実行してもらっているだけです。この点についてはインターフェースメソッドとなんら変わりません。

     

    そう考えていると思っていました。

     

     trapemiya さんからの引用
    これはインスタンスを参照しており、そのメソッドを実行しているから、つまり、そこからインスタンスをお互いに参照し合っていることを指しているのだと思うのですが、これを指しているのであれば、私はこれが問題であるとは考えていないのです。したがって、これが一方向性であるならば、何のために一方向性を守らなければならないのかがわからないのです。相手に関係なくコードを改修できるという回答が返ってきそうですが、これはインターフェースとて同じことです。"おそらく理由として弱い"と言われていますので、くどかったかもしれません。

     

    そう説明されてしまうと、もはや理由は 『実際には必要最小限でないものを参照として渡しているのが気に入らない』 くらいしか思いつかないです。 そしてそれらはインターフェイスというカプセルで一応は守れていると言えるので、大した問題でないというのもすでに会話に出ていますね。 ここまでくると参ったの一言です。

     

     trapemiya さんからの引用
    まどかさんとのやりとりとかぶってきたので、あらためてまとめを作成しているところです。あくまで私が勝手に考えていることなのですが、そう言わず、よかったらまた突っ込んでください。私の今の一番の関心ごとは一方向性です。

     

    trapemiya さんの概念を前提にすると、一方向性についてはたぶん違いというものはないと思います。 平日は営業で外に出ることが多いのでなかなか返信できないです。 旅に出ます。 探さないでください。

    2008年11月25日 6:33
  •  じゃんぬねっと さんからの引用

    発端となった、こちらの元質問である回答については trapemiya さんもイベントの方が良いと仰っているので、それ以外の場合は臨機応変で場合によるとします。

     

    私も同じ意見です。結局、採用するポリシーに基づいて、ケースバイケースにしかならない気がします。

     

     じゃんぬねっと さんからの引用

    ここの捉え方が相違しているので当然結論が分かれてしまうわけですね。 私はイベントはインターフェイスよりもっと特化した部分で扱うという考え方です。 今回のような場合は 「実行するものを呼び出す」 より 「そのタイミングになったよと独り言を言う (捕捉したいヤツがその後勝手に何かしろ)」 が良いと考えています。 でないと全部インターフェイスで実装可能ですし、その理論でいくとまさに Java と変わらないということになります。 どういうことかと言うと、Java を専攻している方から 『プロパティはメソッドが特化したもので不要』 という意見を聞きますが、これと似たようなものだということです。 私が自作イベントを使っている目的の大半は 「データ (表示も含む) の更新」 ですが、これをインターフェイスで置き換えられると、もうイベントの出番がほとんど失せてしまいます (自作コントロールではそれなりに出番がありますが)。

     

    うまい例えですね。

    技術的にはイベントでもインタフェースでも大差ないと思うのですが、インターフェースだとインターフェースが増えた時に管理が大変、イベントに比べてたぶんコーディング量が多いというデメリットがあるのではないかと思い始めています。
    なので、あとはポリシーじゃないでしょうか? こればっかりですが・・・。

     

     じゃんぬねっと さんからの引用

    イベントの基本は 「発火したらそれまで」 ですね。 今回の話題にあがった半リアルタイムの連動はデータが同じであるという前提で話を進めていたので、戻り値的なものは必要ないと考えていました。 戻り値を必要とする場合は、その時点で 2 つがかなり密接に関わっている (同位置で通信し合っている) と言えるので、もはや呼び出し元、呼び出し先という関係でない方が正しいような気がします。

     

    この件に関しては今回の前提というか本質的な議論からは外れると思いので、参考程度と思っています。

     

     じゃんぬねっと さんからの引用

    ここまで来ると仕様変更を考えるようになります。 どうしても仕様変更ができない場合はインターフェイスを使った方が良いです。 もちろんイベント + α でやってできないことはありませんが、この状況でイベントを使うのは私もイケてないと考えます。 この前提であれば trapemiya さんの勝利ですね。 Let's ファンファーレ。

     

    先ほども述べたとおり、本質から外れるのでちょっと微妙ですねw

     

     じゃんぬねっと さんからの引用

    だとすると、当初 trapemiya さんが話題に出した 「メソッド名を揃える」 というのは何を指しているのでしょうか?

     

    単に見通しがよくなる程度しか考えてないです。まぁ、無理やり考えたメリットとも言えるw

     

     じゃんぬねっと さんからの引用

    そう説明されてしまうと、もはや理由は 『実際には必要最小限でないものを参照として渡しているのが気に入らない』 くらいしか思いつかないです。 そしてそれらはインターフェイスというカプセルで一応は守れていると言えるので、大した問題でないというのもすでに会話に出ていますね。 ここまでくると参ったの一言です。

     

    こちらこそ私の回答まで先読みして書いていただき、何も言うことがありません。さすがです。

     じゃんぬねっと さんからの引用

    trapemiya さんの概念を前提にすると、一方向性についてはたぶん違いというものはないと思います。

     

    私が言っていることが正しいか間違っているか別にして、その理解が早いので会話が楽です。

     じゃんぬねっと さんからの引用

     平日は営業で外に出ることが多いのでなかなか返信できないです。 旅に出ます。 探さないでください。

     

    私もさっき2時間の会議から帰ってきたところです。ちょっとペースを落とします。今晩はゆっくりします。まだボジョレーあるし。チーズは無い。(涙)

    2008年11月25日 8:58
    モデレータ
  • ちょっと昨晩考えたことです。(睡眠時間がぁ~。) 誰に向ってというわけではなく、ブログを書く感覚で書いています。

     

    まず、なぜ私はイベントばかりじゃやなく、インタフェースも使っているんだろう?という自問から始まりました。

     

    私がイベントに対して持っているイメージはコールバックです。相手が決まったタイミングで実行してもらうです。言い方を変えれば、何か事が起きた時にそれを知らせてもらって実行すると言うこともできます。一般的なイメージは後者だと思います。私の知る限り、そのように解説してある本がほとんどですが、まぁ、これはどちらでもいいでしょう。見方の違いだけですから。しかし、どのような仕組みで実現されているのかを知っておくことは理解を深めるでしょう。また、イベントはその仕組み上、クラスを疎結合にすることができます。しかし、イベントはクラスを疎結合にすることにおいて、必要条件でも十分条件でもありません。

     

    イベントの主目的は疎結合を実現することではなく、コールバックだと思うのです。でなければ、イベントに複数のイベントハンドラを登録できるようにする機能はおまけ程度の話になってしまうことでしょう。おまけとはちょっと言いすぎかもしませんが。
    一方でインターフェースは純粋にクラスの結合を実現するものであると思います。インターフェースのおかげで疎結合になり、かつ安全に相手とやり取りができるようになります。そう、このやり取りを実現することが重要なんです。つまり双方向性です。
    世の中には双方向でないと困るものがたくさんあります。パソコンとUSBメモリ、携帯電話、新幹線・・・どれも一方向だと困るものばかりです。なのに、なぜ、何のために一方向性を敢えて目指さないといけないのでしょうか? 私は逆で、双方向性をインターフェースを利用して作り出そうとしている・・・。もちろん一方向性を否定するわけではありませんが、双方向な場合が便利な場合もあります。
    例えばインターフェースメソッドの戻り値を受け取るということは双方向性の実現です。

     

    bool メソッド成功したかな失敗したかな = Ihoge.更新だぜ();

     

    双方向性だとお互いに依存関係が出て困ってしまうのでしょうか? いや、きっとそうではありません。インタフェースが疎結合に保ってくれているからです。インタフェースという規約のなかでお互いをお互いに干渉するルールを守るのであれば、相手がどう変化しようとお互い知ったことじゃありません。例えばパソコンとUSBメモリはUSBというインターフェースでつながりますが、USBインターフェイスの規約を守るのであれば、パソコンがどんなに変化しようが、はたまたどんなUSBメモリに挿げ替えようが、両者は協調して作業を続けることができます。

     

    私は.NETを初めて勉強した時、暗黙のうちに、疎結合を実現するのはインターフェース、イベントは通知という印象を受けました。(後にイベントはコールバックと考える方が自分的にすっきりするようになりました。)

    確かにイベントが疎結合になる仕組みを知った時には感動した覚えがあります。しかし、それでも私はそれを疎結合を実現するための道具として第一候補から外したのです。いや、正直に言います。疎結合の道具として使う発想がありませんでした。だから、その時の印象のまま未だに使い分けています。

     

    イベントを疎結合の道具にするのは少し裏ワザというか、現場での実務の経験から出てきたのではないかと思います。私が不勉強なだけでしょうか、そのような観点から解説してある本や記事に出会ったことがありません。イベントの実態はデリゲートです。デリゲートのおかげで疎結合になるのですが、デリゲートがクラス同士を疎結合にするために作成されたとは到底考えられないのです。デリゲートを使えばクラスを疎結合に保つようにプログラミングできるということであって、インタフェースのように最初から疎結合を目指したものではないと思うのです。もし、.NETの設計者が考えもしなかったところで現場で生み出されたものであるならば、それは素晴らしい英知だと思います。なぜなら、インターフェースのようにインターフェースという余分なものを管理する必要がなく、インターフェースに比べて大概の場合コーディング量が少なくなると思うからです。これは工数を落とす上で、文句なく実践的なことです。

     

    現在、私はイベントだけではなく、インターフェースも使います。イベントは通知の機能のみで使うことしかありません。このスレの元々の回答でイベントによるのがベストであると思ったのも、疎結合という理由ではなく、あるタイミングで両方のフォームが連動すれば良いと思ったからです。つまり通知に着目しています。加えてコードが単純であったからです。かつ、インターフェースを設けてまでクラスが密接な関係を取る必要はないと思ったからです。

     

    繰り返しになりますが、イベントで疎結合に保つ方法を否定するわけではありません。それどころか、コーディング量も減るし、工数も落とせるのではないかと思っているぐらいです。
    そこで辿り着いた私の結論は、ポリシーの違いというものです。私はクラスの疎結合を実現するためにイベントを第一に考えないというだけです。それよりもオブジェクト同士の関係を第一に考えるというだけです。これはアプリケーションの動作という観点から見れば場合によって余計になるかもしれません。しかし、ここはポリシーとしか言いようがないのです。


    これまで考察してきたように、イベントを使う場合とインターフェースメソッドを使う場合で、決定的な違いは見つかっていません。なぜなら、イベントもインターフェースメソッドも、これまで繰り返し述べてるように、本質的な仕組みの上で違いがないからだと思います。つまりどちらも、呼び出し元と呼び出し先がレベルの差こそあれ、必要な疎結合は満たしている、呼あび出し先が呼び出し元のメソッドを呼んでいるという点で変わりがないからです。

     

    いずれにしてもイベントによる疎結合実現については私にとって貴重な体験となりました。今のところ以上のように考えていますが、自分の考え方が絶対に正しいとは思っていませんので、今後の経験でまた意見が変わるかもしれませんが、とりあえず中締めということにさせていただきます。これで打ち切るという意味ではありません。でも、少なくともペースは落としましょうw


    #今晩は寝ます。

    2008年11月25日 9:18
    モデレータ
  • #だんだん見えてきました。

     

    やはり、双方がお互いに型を持つことを許容するか否かですかね。

    特急しらさぎ管区からすると、

    Form1がForm2を利用する立場である以上、Form2のコードにIForm1型ましてやForm1型が出てくることはない

    この一点です。

     

    trapemiyaさんの「イベントもインターフェースも結局同じ」というのは

    いわゆるデリゲートリストを見て呼び出すのがForm2であり、

    それがForm1のインスタンスメソッドという理由ということですよね。

    で、イベントの場合は実行時解決の結果と捉えていますので、違うと認識しています。

    その証拠として、Form2にForm1型が出てこないことです。

     

    #興味半分

    例えば、次は許容されるのでしょうか?

     

    Code Snippet

    Public Class A

        Public _B As B

    End Class

    Public Class B

        Public _A As A

    End Class

     

     

    2008年11月25日 9:28
  •  trapemiya さんからの引用

    例えばパソコンとUSBメモリはUSBというインターフェースでつながりますが、USBインターフェイスの規約を守るのであれば、パソコンがどんなに変化しようが、はたまたどんなUSBメモリに挿げ替えようが、両者は協調して作業を続けることができます。

     

    #依存の一方向性が必須という主張であるとご理解していたら誤解でありこちらの至らぬところです。

     

    この出された例は、パソコンとUSBメモリはお互い知らない同士です。

    #なので、USBインターフェースばんざーい、です。

    私は今回のパターン、つまりForm1がForm2をNewしている(知っている)という前提で常に書いています。

    そんなことわかってると言われたら、それはそれで困りますが。

     

    ちなみに最近はインタフェース大好きかも。

    というより馬鹿の一つ覚え継承から抜け出した。
    2008年11月25日 9:42
  •  trapemiya さんからの引用
    うまい例えですね。

    技術的にはイベントでもインタフェースでも大差ないと思うのですが、インターフェースだとインターフェースが増えた時に管理が大変、イベントに比べてたぶんコーディング量が多いというデメリットがあるのではないかと思い始めています。
    なので、あとはポリシーじゃないでしょうか? こればっかりですが・・・。

     

    増えた時のお話ですが、インターフェイスは間に入り込むものですから、複数であっても複数管理できるインターフェイス専用の何かを作れば良いと思います。 まったくの別物であったらそれぞれ別々で作られなければいけませんが、これはイベントでも同じですよね。

     

     trapemiya さんからの引用
    この件に関しては今回の前提というか本質的な議論からは外れると思いので、参考程度と思っています。
    先ほども述べたとおり、本質から外れるのでちょっと微妙ですねw

     

    trapemiya さんからすると、じゃあいつインターフェイス使うの? と思われるのかなと思い今回の話題に近そうな実例を挙げてみたんです。 気にせんでください。

     

     trapemiya さんからの引用
    単に見通しがよくなる程度しか考えてないです。まぁ、無理やり考えたメリットとも言えるw

    本当に無理矢理ですね。 こちらも人のことは言えませんがw

     

     trapemiya さんからの引用
    世の中には双方向でないと困るものがたくさんあります。パソコンとUSBメモリ、携帯電話、新幹線・・・どれも一方向だと困るものばかりです。なのに、なぜ、何のために一方向性を敢えて目指さないといけないのでしょうか?

     

    「一方向性を目指す」 というのは少し違うと思います。 例であげられたものは双方向でないと困るものばかりです。 一方向だけで不便しないなら意味がないので双方向にはしないものとは比べてはいけないと思います。

    2008年11月25日 10:28
  •  まどか さんからの引用

    やはり、双方がお互いに型を持つことを許容するか否かですかね。

    特急しらさぎ管区からすると、

    Form1がForm2を利用する立場である以上、Form2のコードにIForm1型ましてやForm1型が出てくることはない

    この一点です。

     

    そうですね。そこが焦点です。

     

     まどか さんからの引用

    trapemiyaさんの「イベントもインターフェースも結局同じ」というのは

    いわゆるデリゲートリストを見て呼び出すのがForm2であり、

    それがForm1のインスタンスメソッドという理由ということですよね。

     

    その通りです。正確にはForm1のインスタンスメソッドを呼び出すことと、メソッドを呼び出すということに関して同等ということです。

     

     まどか さんからの引用

    で、イベントの場合は実行時解決の結果と捉えていますので、違うと認識しています。

    その証拠として、Form2にForm1型が出てこないことです。

     

    インターフェースを実装したForm2もそれだけの存在でコンパイルが通ります。Form1を必要としません。どのようなクラスがインターフェースを経由してつながってくるのか実行時までわかりません。これは実行時解決じゃないのでしょうか?

     

     まどか さんからの引用

    例えば、次は許容されるのでしょうか?

     

    ずっと問題になっているのはこのパターンです。お互いにお互いのインスタンスを持つ場合ですね。
    このことにのみに着目すれば(疎結合の問題は除く)、私の見解としてはどちらでもないです。そのコードに問題があるということを即座に示せない以上、ポリシーによるとしか言いようがないと思うんです。
    ご提示されたコードですが、一見気持ち悪く見えるのですが(実は私もです)、人間の感覚は時に当てにならないこともあります。このようなパターンは標準の.NETのクラスで許容されているケースをいくつか見つけることができます。例えば先に出たMdiParentプロパティ、Form.ShowDialog(Me)なんかのパターンです。

     

    念のためですが、ポリシーなら何でも良いというのではありません。明らかに誤ったポリシーはもちろんダメです。したがってそれ以外のポリシーはポリシーとして認めざるを得ません。例えばForm2がForm1の厳密な型を受け取るようになっていた場合(通常は私はしませんが)、ポリシーとしてOKという人がいれば(もちろん弊害を理解した上で)、それはそれで私は認めます。
    認めないのは明らかに問題を含んでいるコードで、例えばSQL文を文字列で組み立てるのがポリシーであるという人は、私は認めないでしょう。それはポリシーではなく、むちゃくちゃというもんです。

    2008年11月25日 14:19
    モデレータ
  •  まどか さんからの引用

    #依存の一方向性が必須という主張であるとご理解していたら誤解でありこちらの至らぬところです。

     

    思いっきり誤解してましたぁ。日本語って難しい・・・

     

     まどか さんからの引用

    私は今回のパターン、つまりForm1がForm2をNewしている(知っている)という前提で常に書いています。

    そんなことわかってると言われたら、それはそれで困りますが。

     

    知ってます。ちなみにインタフェースを用いるパターンもそのつもりで私は書いていました。というかForm1とForm2しかないので、Form1がForm2をnewする以外に無いと思うのですが・・・。ごめんなさい、よくわかってないです。

     

     まどか さんからの引用

    ちなみに最近はインタフェース大好きかも。

     

    多重継承をやめてインターフェースを発明した人は天才だと思います。

    2008年11月25日 14:25
    モデレータ
  •  じゃんぬねっと さんからの引用

    増えた時のお話ですが、インターフェイスは間に入り込むものですから、複数であっても複数管理できるインターフェイス専用の何かを作れば良いと思います。 まったくの別物であったらそれぞれ別々で作られなければいけませんが、これはイベントでも同じですよね。

     

    確かに私もインタフェースは一箇所でまとめて定義しています。そういう意味ではあちこちに定義が分散してなくて保守性が良いと言えば良いです。

     

     じゃんぬねっと さんからの引用

    trapemiya さんからすると、じゃあいつインターフェイス使うの? と思われるのかなと思い今回の話題に近そうな実例を挙げてみたんです。 気にせんでください。

     

    大丈夫、OKです。

     

     じゃんぬねっと さんからの引用

    「一方向性を目指す」 というのは少し違うと思います。 例であげられたものは双方向でないと困るものばかりです。 一方向だけで不便しないなら意味がないので双方向にはしないものとは比べてはいけないと思います。

     

    最後の文の意味がはっきりわからなかったのですが、たぶん、双方向性でなければ成り立たないものばかりを引き合いに出して(つまり、一方向性で十分な例を出さず)、一方向性を否定するのはおかしいということですよね。であれば確かにご指摘の通りです。
    一方向性の話題を最初に持ち出されたまどかさんも言われていましたが、私はみなさんが一方向性をどのような場合でも実現しなければならないというように誤解していたので、一つでも双方向性が必要な例を挙げれば十分だと思っていたのです。
    これはどうやら私の誤解でした。ですから、じゃんぬさんのご指摘の通り、筋が通らない文章になっていると思います。ご指摘、ありがとうございます。

    2008年11月25日 14:51
    モデレータ
  • こんにちは。中川俊輔 です。

     

    皆様、回答ありがとうございます。

    すごく勉強になりそうな議論が繰り広げられたみたいですね

     

    しげちゃんさん、フォーラムのご利用ありがとうございます。

    勝手ながら、有用な情報と思われる回答へ回答済みチェックをつけさせていただきました。

     

     

    今後ともフォーラムをよろしくお願いします。

    それでは!

    2008年12月12日 9:30