ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

手作りネットプロトコル工房コミュのオブジェクト指向脳の獲得方法

  • mixiチェック
  • このエントリーをはてなブックマークに追加
最近オブ脳=オブジェクト指向の脳という言葉をよく見かけます。 オブジェクト指向がわからない... どうやったらわかるようになるんだろう... という疑問に対する一つの答えとして、オブジェクト指向っていうのは日常の思考パターンから違うんだ、「オブジェクト指向の脳」を持たないとだめなんだ、ということのようです。

ここで、ためしに、一言叫んでみたいと思います。

今  さ   ら   オ  ブ  脳  を  得  る  の  は  無  理  で  す  

       *  *   諦  め  て  く  だ  さ  い  * * 

何故ならば、もしもあなたがオブ脳を得る事が出来る人であれば、こんな文章を読むヒマも無くすでに理解できていたはずだからです。 どんなに努力しても死ぬまでそのままでしょう。

... もしあなたがこういわれたとしたら悔しいでしょうか。しかし、意外と真実を言い当てているような気ませんか。 だって、もうずいぶんと長い間オブジェクト指向に苦しめられているじゃないですか。


これを解決する方法は存在します。
それを解決する方法は一つだけです。

--- --- --- --- --- --- --- --- --- --- --- ---

今までに、こういう考え方はしたことはありますか?

例えば、次のような質問があったとします。

「ネコとは何でしょうか。 敢えてネコとか動物とか昆虫とかの単語を使わないで説明してみてください。 」

近所の子供に聞いたらどういう答えが返ってくるでしょうか。

... 「ネコは、足が4本あって、しっぽがあるよ!」

でも、そういう生き物って他にも沢山いますよね。

「ひげがあって、毛がつやつやで、なでるとすべすべしている!」

それってイヌもそうじゃないですか。

... 「いや、違うよ! イヌはワンワンと吼えるけど、ネコはニャァニャァとなくよ!」

じゃぁ、にゃぁにゃぁとないたら、ネコなんですか? ウチのネコは無口なので全く鳴きません。

...「ネコはつめが生えていてひっかくよ!、イヌはつめが短いのであんまりひっかかないよ!」

なるほど ... そういう見方もありますね。 でも、こうやって特徴をあげていくと色々と見えてくるものがありますね。

... では、次に行きます。

イヌとネコの違いって何ですか?

...「イヌもネコも目があり口があり鼻がある」
...「イヌもネコも動き回る」
...「イヌもネコもひげがある」
...「イヌもネコも足は4本だ」

だけど

...「ネコは長いツメがあるけどイヌは無い」
...「ネコは塀の上を歩くけど、犬は無理だ」
...「イヌは言うことを聞くけどネコは聞かない」

... こうやって特徴を挙げていくと、それぞれの特徴の中にも共通の特徴と独自の特徴があることがなんとなく見えてきます。

じゃぁ ネコとアリの違いって何でしょうか。

... 「ネコもアリも動き回る」
... 「ネコもアリも目があり口がある」

だけど

... 「アリには鼻が無い。その代わり触覚がある」
... 「ネコは足が4本だけどアリは6本である」
... 「ネコは毛が生えてるけどアリは無い」
... 「ネコはひげがあるけどアリは無い」
... 「ネコは鳴くけどアリは鳴かない」
... 「アリは時々羽が生えているやつがいるけど、ネコには無い」


この様にして究極まで突き詰めてみれば、 共通点を見つけてまとめることが出来ます。

人はこうして意識的にしろ無意識的に、物事の特徴を挙げていった結果を共通の特徴を軸にまとめて分類しています。 例えば、今、人間は、身近にいるもので手足が4本ある物を、特に「動物」と呼び分類しています。 手足が6本あるものは、イヌネコとは比較して多くの違いがあるので、特に「昆虫」と呼んで分類しています。

もちろん、人間が住むこの世界に 「動物」という生物が居るわけではありません。 ある共通の特徴を持っているものを便宜上「動物」と呼んでいるだけです。

この様に、ある共通の特徴を持ったグループをまとめ、名前をつけることを総称して『抽象化』といいます。

抽象化というと、何だか難しいことの様な気がしますが、考えてみれば イヌ・ネコ という言葉も抽象的な概念だといえます。 だって、みちばたで寝転んでいるのは、イヌやネコではなく「うちのシロ」や「隣のタマ」な訳ですから。

しかし、何故こういうややこしいことをしてまで、『抽象化』という作業をするのでしょうか。 それは、抽象化するとよいことが沢山あるからです。

--- --- --- --- --- --- --- --- --- --- --- ---

例えば、動物の子を育てなければいけないとします。

育てなければいけない子がイヌの子だったとします。

例えあなたが、イヌの子を育てたことが今まで無くてもイヌの子であれば人間の子と同じ様にミルクをあげればよいとわかります。 同様にたとえ育てなければいけない子がネコの子でも直感的にミルクをあげれば育てられるとわかります。

私たちは、常日頃こうして無意識の内に様々なことを判断しています。ですが、何故イヌネコの子をヒトの子と同じ様に扱えば育てることが出来るとわかるのでしょうか。

それは、イヌもネコも『抽象的』に見れば人間と同じ哺乳類だということを知っているからではないでしょうか。 例えば、哺乳類でさえあれば、イヌの子でもネコの子でもヒトの子と同じ様にミルクをあげてしばらく寝かせてあげればよい、とわかりますし、だからこそ、万が一 全く未知の動物の子を育てることになったとしても、哺乳類でさえあれば、ミルクをあげて育てることが出来るとわかります。

逆に、アリの子を育てようとするときミルクをあげても育てることは出来ないとわかります。 アリをミルクで育てることが出来ないと直感的に理解できるのは、私たちが、アリが抽象的に見て哺乳類ではないと知っているからに他なりません。

この様に、抽象化したものは、その抽象化した範囲の中で同様に扱うことが出来ます。 一度確実に抽象化してしまえば、その対象がイヌであるかネコであるか、問題としなくても構わないので、考える量を減らして頭を休めることが出来ます。 この頭を休めることはとても大切なことです。 こうして様々な方法を使って頭を休めることによって、他の事に頭脳パワーを使えるようになります。 そして、より規模の大きなことを考えることが出来るからです。

この様に抽象化すると考える上でたくさんの便利な点があります。

--- --- --- --- --- --- --- --- --- --- --- ---

しかし、これがオブジェクト指向とどういう関係があるというのでしょうか。

これは大いに関係があります。 実は、プログラミングというのは、この『抽象化』という作業を、自分の頭脳で考える作業に他ならないからです。


例えば、ビデオデッキと DVDプレーヤーをクラス化したいとします。

ビデオデッキの特徴とは何でしょうか。
はじめにビデオデッキの特徴を挙げてみたいと思います。

  ・メディアはビデオテープ。
  ・テープをセットする。
  ・巻き戻しする。
  ・早送りする。
  ・再生する。
  ・一時停止/再開する。
  ・停止する。
  ・テープをイジェクトする。

と、いったところでしょうか。

プログラムとして書くと次のようになるかもしれません。

  class VideoTape {
  }
  
  public class VideoDeck {
    public void set( VideoTape tape ) {
    }
    public VideoTape eject() {
      return null;
    }
    public void cue(int millisec) {
    }
    public void rewind(int millisec) {
    }
    public void pause() {
    }
    public void restart() {
    }
    public void play() {
    }
    public void stop() {
    }
  }

と、いったところでしょうか。

次にDVDプレーヤーの特徴を挙げてみたいと思います。

  ・メディアはDVD光ディスク。
  ・DVDをセットする。
  ・巻き戻しする。
  ・早送りする。
  ・再生する。
  ・一時停止/再開する。
  ・停止する。
  ・DVDをイジェクトする。

同じ様にクラス化してみたいと思います。

  class DVDDisk {
  }
  public class DVDDeck {
    public void set( DVDDisk tape ) {
    }
    public DVDDisk eject() {
      return null;
    }
    public void cue(int millisec) {
    }
    public void rewind(int millisec) {
    }
    public void pause() {
    }
    public void restart() {
    }
    public void play() {
    }
    public void stop() {
    }
  }

と、いったところでしょうか。

こうして実際に書いてみると、ほとんど同じメソッドが並んでいます。
実際の使い方をみてみても、ほとんど同じではないでしょうか。

  1.ビデオかDVDを入れる。
  2.再生する。
  3.見る。
  4.見終わったら停止する。
  5.ビデオかDVDを取り出す。

実際にプログラムもかいてみましょう。

もしもDVDだったら ...

  (例1)
    DVDDeck deck = new DVDDeck();
    DVDDisk disk = new DVDDisk();
    deck.set( disk );
    deck.play();
    while ( deck.isPlaying() ) {
      this.watch( deck );
    }
    deck.stop();
    deck.eject();
  
  もしもビデオだったら...
  
  (例2)
    VideoDeck deck = new VideoDeck();
    VideoTape tape = new VideoTape();
    deck.set( tape );
    deck.play();
    while ( deck.isPlaying() ) {
      this.watch( deck );
    }
    deck.stop();
    deck.eject();

出来上がりました。

こうしてみてみると、ほとんど同じ処理をしているのに 二つのプログラムを書かなければいけないことがお判りいただけますでしょうか。

実は、これは、ソフトウェアを書く上で絶対にやってはいけないことなのです。

もし、ビデオを再生するプログラムを変更する様な状況になったとします。そういう場合、高い確立でDVDも変更しなければならないのではないでしょうか。 実際に現場で作業していると、そのようなケースに非常によく出会います。

何故でしょうか。 それは、抽象的に見れば、「ビデオを見る」という行為の意味が、「DVDを見る」という行為の意味とほとんど変わらないからです。 プログラム上のビデオを見るという行為を変更しようとすれば、必然的にDVDを見る行為も変更するのが自然だからです。

また、このようなスタイルで強行的に開発を進めると、往々にして次々に同様なロジックを書くことを強いられる苦しい状況に陥る場合が多いのです。 そして、全体の作業量は二次関数的に増大し、最終的にはプロジェクトが破綻します。

どうすればよいのでしょうか。

正にこれのドンピシャの解決策が 継承 = extendsです。 これは、正にこの問題の解決策、複数の抽象的に同じクラスを結びつけるための機能です。

先ほどの例で行けば、ビデオデッキもDVDプレーヤーも 抽象的に見れば同じ「オーディオ再生装置」といえます。 ビデオテープもDVDディスクも形こそ違えど抽象的に見れば同じ「メディア」です。

それをプログラムとしてあらわすと、

  // Mediaクラス : 抽象的なメディアをあらわす
  class Media {
  }
  // Playerクラス : 抽象的なオーディオ再生装置をあらわす
  public class Player {
    public void set( Media media ) {
    }
    public Media eject() {
      return null;
    }
    public void cue(int millisec) {
    }
    public void rewind(int millisec) {
    }
    public void pause() {
    }
    public void restart() {
    }
    public void play() {
    }
    public void stop() {
    }
  }
  

  // DVDDiskクラス : メディアの一例 DVDのディスク
  class DVDDisk extends Media {
  }
  // DVDDeckクラス : オーディオ再生機器の一例 DVDデッキ
  public class DVDDeck {
   @Overrides
    public void set( Media tape ) {
    }
   @Overrides
    public Media eject() {
      return null;
    }
   @Overrides
    public void cue(int millisec) {
    }
   @Overrides
    public void rewind(int millisec) {
    }
   @Overrides
    public void pause() {
    }
   @Overrides
    public void restart() {
    }
   @Overrides
    public void play() {
    }
   @Overrides
    public void stop() {
    }
  }
  
  // VideoTapeクラス : メディアの一例 ビデオのテープ
  class VideoTape extends Media {
  }
  
  // VideoDeckクラス : オーディオ再生機器の一例 ビデオデッキ
  public class VideoDeck {
   @Overrides
    public void set( Media tape ) {
    }
   @Overrides
    public Media eject() {
      return null;
    }
   @Overrides
    public void cue(int millisec) {
    }
   @Overrides
    public void rewind(int millisec) {
    }
   @Overrides
    public void pause() {
    }
   @Overrides
    public void restart() {
    }
   @Overrides
    public void play() {
    }
   @Overrides
    public void stop() {
    }
  }

この様に書くことが出来ます。 ですが、しかし、この様に書くことでどのような利点があるのでしょうか。 実は、この様に書くことにより、扱い方=ビデオ/DVDの見方を統一することが出来るという大きな利点があるのです。

先ほどのプログラム(例1)(例2)は、

  void playAndWatch( Player player,Media media ) {
    deck.set( media );
    deck.play();
    while ( deck.isPlaying() ) {
      this.watch( deck );
    }
    deck.stop();
    deck.eject();
  }
  
  (例1)
    VideoDeck deck = new VideoDeck();
    VideoTape tape = new VideoTape();
   playAndWatch( deck,tape );
  
  (例2)
    DVDDeck deck = new DVDDeck();
    DVDDisk disk = new DVDDisk();
   playAndWatch( deck,disk );

この様に書き換えることができます。

一つのメソッドとして統合できてしまいました。

実は、これで、もしも「再生する」という行動が変化した場合でも、playAndWatch()メソッドを変更すれば、DVDの場合でもビデオの場合でも等しく動作を変更できるのです。

また、この様に書くことにより、例えば、VideoCDクラスを追加したとしても、プログラム全体には何も変更を加えなくてよいという、大きな驚くべきメリットがあります。 (これは『哺乳類でさえあればミルクをあげればよい』という比喩と全く同じといえないでしょうか。)

ところで、予断になりますが、見方によってなんともいえない機械というのも結構あります。例えば「テレビデオ」は、どうすればよいのでしょうか。 この機械はビデオの操作方法も持っていますし、テレビの操作方法も持っています。 先ほどのビデオデッキとDVDプレーヤーの場合は、これらは『再生機器である』とはっきり断言できましたが、ところがテレビデオの場合、これは何である、とはっきり断言できません。

実は、この様な場合でも、interfaceという機構を使えば抽象的にプログラムできます。

他にも、interfaceを使えば、ビデオデッキは『再生機器』という切り口で見ることも出来るけど、『音声を出す機械』という切り口で見ればラジオと同じともいえる、といった複数の切り口を持っているケースもプログラムで表すことが出来ます。


この様にしてみると、プログラミングという作業が、抽象化する=共通点を挙げてまとめるという作業と非常に近いことが、お判りいただけるのではないでしょうか...。

--- --- --- --- --- --- --- --- --- --- --- ---

この思考パターンは、残念なことですが日本人が最も苦手とする思考パターンだと思います。

学校では、「既に誰かが考えた」分類を丸暗記ばかりさせされて、自分で分類を作る方法など誰も教えてくれなかったのではないでしょうか。 自分で考えると当然間違えることもあります。 日本では、テストで間違えれば点数はくれません。そして、その結果、卒業も出来ません。 親から早く卒業しろとせかされ叱られます。親不孝と罵られます。 反論の余地はありません。 こうして、日本人は日本に生まれ、自分で考えるのはよくないことだと繰り返し繰り返し刷り込まれます。

確かに、人が考えた結果を覚えれば、間違えることはありません。 自分で考えれば当然間違えるかもしれません。 それは他人が考えたことを覚えることよりもはるかに危険な行為です。

ですが、自分で考えて間違えた経験は、絶対に忘れることの出来ない苦い思い出と共に、絶対に教わることは出来ない『次回から絶対に間違えない黄金の才能』を与えてくれます。

自分で考えてさえいれば、最終的には誰にもささえられずに、一人で歩くことが出来るようになります。自分で歩けば、最初は転ぶかもしれないけども、何度も転ぶうちに、だんだんと転ばなくなるようになるものです。 そうして、自分が本当に行きたい場所に自分で歩いていけるようになります。

転ばないようにと、自力で歩く事自体を禁止しているのが、今の日本です。日本というのは、この大切な「失敗する権利」が全て綺麗に剥奪されています。 この日本人の心に打ち込まれた深いくさびの存在をはっきりと意識し、自分で考えて失敗する権利を主張し、死ぬ気で徹底的に自分の思考パターンを叩きなおさない限り、日本のプログラマーがいわゆる「オブ脳」を得ることは無いでしょう。

自分で考える時は、むしろ、失敗を恐れないことが一番大切なことになります。これは、日本の学校で教わることとは正反対のことです。 誰かが失敗した時、失敗を恐れずに果敢に挑戦したことを褒める日本人がどれくらいいるでしょうか。

「100の他人が考えたことを知るよりも、1つだけでもよいから自分で考えたことを持つことのほうがどんなに大きな価値があることなのか。」 これこそが、自分で考えるということの真髄だと思います。


--- --- --- --- --- --- --- --- --- --- --- ---

実は、この考え方は、プログラミング独自の考え方ではありません。

Javaの いろいろな考え方 --- class interface abstract class や 内部class 無名 class etc.etc は 西洋哲学の思想を脈々と受け継いでいます。 ですから、普段からこういう考え方をしなれていないと、プログラミング技術をひとつひとつ勉強して知ったとしても、その技術がどうやって使うものなのかさっぱり見当もつかないということになります。

プログラミング言語は、そのほとんどが西洋で開発されたものです。 だから、西洋思想を知り、その勉強の一環として英語も勉強することにより、より深い理解が得られます。

例えば、ほとんどのプログラミング言語は英語として簡単に読めるように出来ています。

perl の

  exit if a == 10;

という書き方をご存知ですか?

日本では後置IFと呼ばれプログラミングに全く関連の無い技術としてほとんど注目されていません。 ですが、これには、プログラムが英語として自然に読めるようになる、という大きな意味があります。

これは、プログラミングという作業を自分の思考パターンにいかにして近づけるか、という工夫の一つです。

プログラミングするという作業がまさに考えることそのものである、ということに気づいているからこそ、このような工夫が存在するのではないでしょうか。

---

リファクタリングとかデザインパターンとかGOFとか言っている人の10人中89人は あまりオブジェクト指向が得意ではない人ではないでしょうか。 本当に出来る人はほとんどそういう言葉を使いません。

何故でしょうか。

リファクタリングにせよ、デザインパターンにせよ、自分なりによく考えてみれば、自然にあの様なパターンに落ち着くからです。 誰が考えてもあのようなパターンに落ち着きます。

だから、考える力があれば、特に勉強する必要はありません。

逆に、考える力が無いと、多くのパターンを勉強しても、知識ばかりが増えるばかりで、肝心の問題は何も解決しないという状況になりがちです。

だからこそ、自分で考えるという事が一番大切なことなのです。


答  え  は  本  の  中  で  は  な  く  、  す  で  に  あ  な  た  の  中  に  あ  り  ま  す  。

そ  れ  を  つ  か  む  能  力  は  あ  な  た  も  持  っ  て  い  ま  す  。

コメント(3)

こんにちは、はじめまして。

オブジェクト指向の雑談でも、、、

自分が悩ましく思っている点で「モノの認知と抽象化の基準」についてです。

「イヌ」「猫」「アリ」という要素がある場合、
1.「イヌ」「猫」を「哺乳類」、「アリ」を「昆虫」と分類する人もいれば、
2.「イヌ」「猫」「アリ」をまとめて、植物に対する「動物」と分類する人もいれば、
3.「イヌ」「猫」を「哺乳類」、「アリ」を「昆虫」と分類とした上で、
  さらにまとめて「動物」と分類する人もいれば
4.「イヌ」「猫」「アリ」を抽象化せずに、個々のモノと捕らえる人もいると思います。

また、
5.「イヌ」「猫」を「4つ足」、「アリ」を「6つ足」   と分類する人もいるかもしれない。

さらにもう一例を挙げれば、
6.「イヌ」「猫」をモノとして認知せずに、「哺乳類」と「動物」と考えるかもしれない。

よって、何をモノとして認知するかが視点によって異なり、
さらに、それをどのように分類するかも異なります。

これについては、どのようにモノを認知すればO.K.であるか、
また、どのように分類すればO.K.であるか、についての絶対的な基準ないですが、
うまくクラスを作成するコツを経験者はそれぞれ知っていると思います。

この点については、かなり悩ましいです。


余談.性質の違うものを同じとみなして、スーパークラスで
   IF文というPGをみると、、、(T-T

ログインすると、みんなのコメントがもっと見れるよ

mixiユーザー
ログインしてコメントしよう!

手作りネットプロトコル工房 更新情報

手作りネットプロトコル工房のメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング