K.Maebashi's BBS

ご自由に書き込んでください。雑談も可。
テスト書き込みの類はテスト用掲示板にどうぞ

[日付順表示] [日付順インデックス] [スレッド順インデックス]

新規投稿 | 開設者ホームページへ戻る | ヘルプ

[1260] 疑りぶかいあなたのための「オブジェクト指向再入門」を読んで
投稿者:SE
2009/05/15 14:06:45

疑りぶかいあなたのための「オブジェクト指向再入門」を読みました。 部分的に同意できる所もありますが、オブジェクト指向の「本質」はマルチプル インスタンスだと言うのは全く違うと思います。 その論理で行くと、マルチプロセスやマルチスレッドはオブジェクト指向になると 思いますが、これらはオブジェクト指向云々以前から存在する、別の話だと思います。 オブジェクト指向プログラミングの利点は、 「変更がしやすい」事と「変更しても以前の機能が失われない」事です。 簡単に説明します。 先入れ後出し形式のデータ(スタック)をクラス化したとします。 エラー処理を考慮しなければ、大体以下のようになるでしょう。 ----------------------------------------------------------- public class Stack {   private String[] data = new String[100];   private int index = 0;   public Stack(){   }   public void put(String val){     data[index] = new String(val);     index++;   }   public String get(){     String ret = "";     index--;     ret = data[index];     return ret;   } } ----------------------------------------------------------- 例えばこれを修正して、大文字に変換して返す物を使いたいとします。 ----------------------------------------------------------- public class UpperStack extends Stack {   public String get(){     return super.get().toUpperCase();   } } ----------------------------------------------------------- そして、大文字で取得したい場所では、このUpperStackを使うようにします。 ここで重要なのは、基のクラスのStackには全く修正が入らない事です。 そのため、変更により以前の機能のまま使用したい場所には影響がありません。 ちなみに、Stackに別名の大文字で返すメソッドを追加すると言う方法もありますが、 基のソースに修正が入るため、デグレートの危険が発生します。 やたらに継承をしたくない場合は、それでも構いませんが、以下の方式はダメです。 ----------------------------------------------------------- public class Stack {   private String[] data = new String[100];   private int index = 0;   public Stack(){   }   public void put(String val){     data[index] = new String(val);     index++;   }   public String get(boolean up){     String ret = "";     index--;     if(up){       ret = data[index].toUpperCase();     }else{       ret = data[index];     }     return ret;   } } ----------------------------------------------------------- なぜダメかは、構造化プログラミングを行っていて、度重なる修正で スパゲッティープログラム化しているのを見た事のある人なら分かるでしょう。 これを使用している所で、変更の必要ない既存部分にも手が入り、処理にも分岐が 入って複雑化するためです。 適切にオブジェクト指向プログラミングされていれば、修正が入っても劣化せず、 むしろ抽象化され使いやすいクラスになっていきます。 オブジェクト指向プログラミングの目的はこれだけです。 カプセル化、継承や多態化もこれを実現するための手段に過ぎません。 そのため「オブジェクト指向の目的は、再利用性を高める事」は正しいです。 しかしこの場合の再利用性は、関数化などの話ではなく、変更の時の使いやすさを 指しています。 新人が誤解するので「オブジェクト指向はマルチプルインスタンス」と言う記述は 修正か注意書きをしてほしいです。
[この投稿を含むスレッドを表示] [この投稿を削除]
[1261] Re:疑りぶかいあなたのための「オブジェクト指向再入門」を読んで
投稿者:774RR
2009/05/15 14:56:25

「再入門」のそのあたりの記述は、そもそも「インスタンスが複数あっていい」というあたりを理解していないプログラマ向けの文書。 SE氏の指摘は「インスタンスが複数あるのは当たり前」と理解しているプログラマの視点なわけで。 そういう意味で、対象読者層が異なるだけのことだと思う。 あえて言わせていただくと、提示例はやっちゃダメな「実装継承」の典型例であって 俺の後輩君がこんなコードかいてたら0点つけるですよ。 > そして、大文字で取得したい場所では、このUpperStackを使うようにします。 これは、実体が Stack であるインスタンスに対して UpperStack にダウンキャストして使う、としか読めない。 そんな危険なことをさせるわけにはいかないと思うのだが。
[この投稿を含むスレッドを表示] [この投稿を削除]
[1262] Re:疑りぶかいあなたのための「オブジェクト指向再入門」を読んで
投稿者:
2009/05/15 18:53:09

 私にとってOOPを使う最大の理由は。  「カプセル化により見透視のよさ!」これに尽きます。  継承や多態化はそのサポートのために。再利用性は設計の問題であり。OOとは 関係が薄い場合がある。ただし、OOを使っても見透視の悪いコードはいくらでも かける。が、よく整理されたクラスの見透視の良さは、OOが無い言語に比べて 格段にいい。
[この投稿を含むスレッドを表示] [この投稿を削除]
[1265] Re:疑りぶかいあなたのための「オブジェクト指向再入門」を読んで
投稿者:(ぱ)こと管理人
2009/05/16 22:40:50

>その論理で行くと、マルチプロセスやマルチスレッドはオブジェクト指向になると >思いますが、 ならないと思いますが…… まあ、オセロの例で注記したように、マルチプロセスにはオブジェクト指向と似た面は ありますけど。「その論理で行くと」の「その論理」がどういう論理か、教えて いただきたいです。 >例えばこれを修正して、大文字に変換して返す物を使いたいとします。 >----------------------------------------------------------- >public class UpperStack extends Stack { >  public String get(){ >    return super.get().toUpperCase(); >  } >} >----------------------------------------------------------- 774RRさんがすでに書いていますけど、これは典型的な「ダメな実装継承の例」でしょう。 # 「実装継承」でGoogleしてみることをお勧めします。 実のところ「要素を大文字に変換して返すスタック」がどんな時に役に立つのか 想像できませんが、それはまあ、「あくまで例だから」ということにしても、 このケースは、 「要素をgetする側は、大文字が欲しいとき、そのことを意識している」 のでしょうか。 意識しているのであれば、そもそも「stack.get().toUpperCase();」で済む話です。 大文字に変換する、という単純な処理でないのなら、ユーティリティメソッドを 作ればよいでしょう。 そこでわざわざ継承してクラスを作ったって、以下のような問題が起きるだけです。 ・Stackが引数かなにかで渡されたとき、本家StackなのかUpperStackなのか  わからなくて危険。 ・別の誰かがLowerStackを作ったら、いつかマージするの? ・ユーティリティメソッドではprivateメンバにアクセスできないが、  継承なら、protectedにしておけばサブクラスからアクセスできる、というのが  趣旨なら、それはカプセル化の破壊以外の何者でもない。 ところで、SEさんの例では、get()メソッドがオーバーライドされています。 「要素をgetする側は、大文字が欲しいとき、そのことを意識している」のであれば、 仮に継承を使うとしても、getUpper()メソッドをつけることでしょう。 オーバーライドしているということは、 「要素をgetする側は、大文字が欲しいとき、そのことを意識しないで済む」 ということにしたいのでしょうか? # それにしては、get(boolean up)と対比しているのでよくわかりませんが。 もしそうなら、 >そのため、変更により以前の機能のまま使用したい場所には影響がありません。 というわけにはいきません。 この改修により、プログラムにUpperStackという「異物」が実行時に紛れ込むわけで、 「Stackにputしたんだから、当然同じものがgetできるだろう」と思い込んでいる 既存コード(Stackそのものを含む)にはおもいっきり影響を与えます。 しかも、get(boolean up)とは違い、実際に動かしてみなければ検出できない バグになりますからさらにタチが悪いです。 上のほうで『実のところ「要素を大文字に変換して返すスタック」がどんな時に 役に立つのか想像できません』と書きましたが、結城浩さんが「例は嘘をつかない」 と書いておられるように、こういうところで現実のプログラムに即した適切な例が 出てこないなら、おそらくそれは考え方のほうが間違っています。 ひとつ伺いたいのですが、SEさんはどんな本でオブジェクト指向の勉強をされたの でしょうか。 いまどきこんなバリバリの実装継承でオブジェクト指向を説明している教科書は そうそうないと思っていたので、もし新しい本にそういうことが書いてあったのなら 興味があります。ぜひ書名を教えてください。 ところで、私が現在作っているクラスベースオブジェクト指向言語Diksamでは、 「concreteクラスは継承できない」ということにしてしまっています。これは 実装の手抜きではなく、意図して行っています。 ここまでやってしまうと異論はあるかもしれませんが、Effective Javaとか GoFのデザパタ本とかで、かなり昔から、散々「抽象クラス以外は継承するな」と 言われてますし、SEさんのような誤解を防止するためにもこの方がよいのではないかと。 http://java-house.jp/ml/archive/j-h-b/050862.html
[この投稿を含むスレッドを表示] [この投稿を削除]
[1266] Re:疑りぶかいあなたのための「オブジェクト指向再入門」を読んで
投稿者:(ぱ)こと管理人
2009/05/17 20:50:06

> 私にとってOOPを使う最大の理由は。 > > 「カプセル化により見透視のよさ!」これに尽きます。 これなんですが、C++だと、privateなメンバ変数とかは、外から参照すれば コンパイラにエラーで怒られるとはいうものの、.hファイル中には記述されて しまいますよね。Javaだとメソッドの実装も書くことになるのでもっと深刻です。 これでは利用者側の再コンパイルが必要になりますし、ライブラリの実装が 終わる前にアプリケーションを作り始めたいという場合にも困る、ということで、 (Javaで言えば)インタフェースのみ公開してHogeImplみたいなクラスを作る、 なんてパターンが知られています。 私にはこれは必須に思えるので、Diksamではもうちょっと言語で積極的に サポートしたかったんですけどね。うまい文法が思いつかずにJavaと同等に なってしまっています。うーん、いつかそのうち。
[この投稿を含むスレッドを表示] [この投稿を削除]
[1267] Re:疑りぶかいあなたのための「オブジェクト指向再入門」を読んで
投稿者:
2009/05/18 18:28:11

>これなんですが、C++だと、privateなメンバ変数とかは、外から参照すれば >コンパイラにエラーで怒られるとはいうものの、.hファイル中には記述されて >しまいますよね。  カプセル化という言葉に対して、きっちりとした完全な意味を求めてるのだ ろうと思いますが、私はそこまでのことを意識してこの言葉を使っていません。 問題は。  必要なこと意外一切情報を出さないほうがいいのか。内部がある程度想像 できるほうがいいのか?Cはたとえ使えなくともクラスのデータやメソッドが見 える。これが良いか悪いかでしょう。私は後者のほうが気分的には良いです。 使わない情報が見えたとしても、実質的にカプセル化されていれば問題ないと 考えます。  言語の設計において、理想的なものを作っていくのもあります。私の場合は 目的が実現できれば簡単なものでいいと思って設計しています。その代表が #defineです。古い仕様で問題点も内包しますが、実に使いやすく融通が利きます。 今では#defineはあまり良くないとされていますが、私は利点を選びました。
[この投稿を含むスレッドを表示] [この投稿を削除]
[1279] Re:疑りぶかいあなたのための「オブジェクト指向再入門」を読んで
投稿者:(ぱ)こと管理人
2009/05/21 01:45:56

SEさんとの議論がアツいので、こちらの返信が遅くなってしまいました。 > カプセル化という言葉に対して、きっちりとした完全な意味を求めてるのだ >ろうと思いますが、私はそこまでのことを意識してこの言葉を使っていません。 ええと、用語定義の問題と言うよりは、(私の感覚では)かなり実用的な問題でして。 > 必要なこと意外一切情報を出さないほうがいいのか。内部がある程度想像 >できるほうがいいのか?Cはたとえ使えなくともクラスのデータやメソッドが見 >える。これが良いか悪いかでしょう。私は後者のほうが気分的には良いです。 チームで開発するとき、ライブラリとそれを使うアプリケーションがあったとして、 これらを平行して開発することがあります。そういう場合、ライブラリの ヘッダファイルだけ先に作ってしまえばアプリケーション側のコンパイルが通せますが、 その時、空実装のメソッドを暫定で書いて後で差し替えるような作業は バージョン管理が面倒になるので避けたい。また、ヘッダファイルはドキュメント的な 性格も大きいですから、ここに実装やprivateメンバを書いてごちゃごちゃして しまうのも避けたい。 また、ヘッダファイルの依存関係が漏洩するという問題もあるでしょう。 あるライブラリがウインドウに絵を描いたりするのでprivateメンバで windows.hで定義されている型などを使っていたりすると、それを使う人にまで もれなくwindows.hがプレゼントされ名前空間が汚染されてしまったりとか。 ……という話題が昔JavaHouseであったとき、 http://java-house.jp/ml/archive/j-h-b/048357.html#body http://java-house.jp/ml/archive/j-h-b/048360.html#body これを問題と思わない人が多かったようなので、私のような心配をするのは 少数派なのかもしれませんけれども。 > 言語の設計において、理想的なものを作っていくのもあります。私の場合は >目的が実現できれば簡単なものでいいと思って設計しています。その代表が >#defineです。古い仕様で問題点も内包しますが、実に使いやすく融通が利きます。 >今では#defineはあまり良くないとされていますが、私は利点を選びました。 これは同意です。「わかって使う」分には、#defineは便利ですよね。
[この投稿を含むスレッドを表示] [この投稿を削除]
[1281] Re:疑りぶかいあなたのための「オブジェクト指向再入門」を読んで
投稿者:
2009/05/21 21:05:59

>こちらの返信が遅くなってしまいました。 いえいえ、お返事いただけるだけで嬉しいので、気にしないでゆっくりして下さい。 >(私の感覚では)かなり実用的な問題でして。 了解しました >また、ヘッダファイルの依存関係が漏洩するという問題もあるでしょう。 >あるライブラリがウインドウに絵を描いたりするのでprivateメンバで >windows.hで定義されている型などを使っていたりすると、それを使う人にまで >もれなくwindows.hがプレゼントされ名前空間が汚染されてしまったりとか。 賛同です。これは問題ですね。OOP以前C言語の時は、それはキッチリとヘッダーが きれいに分割され必要な所だけが#includeされていたのですが。OOPになって、 必要も無いようなヘッダーが次から次へと#includeされているのを見るのは、 正直止めてほしいと思っています。特にVCはひどい、プリコンパイルヘッダーを 作ったのは苦肉の策ではないかと疑ってしまうほどです。  しかし、現実に自身が作っている内容でも、結局多くのヘッダーが#include してしまっているのを見るにつけ、何かの対策がほしいと思います。 >これを問題と思わない人が多かったようなので、私のような心配をするのは >少数派なのかもしれませんけれども。 私もそうですが、目をつぶっているだけなのかも知れません。  ちょっと真剣に考えて見ます。軽はずみな返事をしたくないと思っているので ちょっと期間をくださ。今は、作っている言語仕様に頭がいっぱいなんです。 いま佳境に入ってて、最近はプログラムではなく仕様書の書き込み書き直しばか りしています。楽しくもあり苦しくもある時間です。  いやほんと、こんな仕様を発表したら、けちょんけちょんにけなされっるので はないかとか、本当に良いんだろうかとか、でも当面第1弾はこれしかないよな~ とか、悩んだりしています。   今作っている言語そしてシステムの最大の目的は。   「簡単なルールを持った言語で、いかに複雑な処理を簡単に書けるか」 なので、熟練のプログラマーのほうが抵抗が大きいのではないかと…  プログラミング言語というものは論理的に整然と矛盾が無く、どんな形でも 記述可能であり。その中においてさえ、書きやすくセーフティーな環境を提供し 見やすさを追求している、と私は思っています。でも、私が目指しているのは。 記述目的を限定することで、自由が無くなる分、普通では考えられないような 記述で複雑なものを簡単に記述すシステムを出してみたい。  大風呂敷はこのへんで終わって、早く実物が出来るようにがんばります。
[この投稿を含むスレッドを表示] [この投稿を削除]