オブジェクト指向基礎学習Ⅱ 平成19年6月20日 森田 彦
学習内容 オブジェクト指向の考え方 オブジェクト指向の実装(Java言語の場合) JBuilderプログラミング総復習
Ⅰ.オブジェクト指向の考え方 1 オブジェクトとは何か? 2 オブジェクトの基本概念 3 オブジェクトの拡張 <内容> オブジェクト指向の考えのエッセンスを学習し、それをプログラム開発に応用した場合にどのようなメリットがあるかを理解する。 <内容> 1 オブジェクトとは何か? 2 オブジェクトの基本概念 3 オブジェクトの拡張
1.オブジェクトとは何か? オブジェクトの例 カプセル化(プロパティとメソッド) オブジェクト指向的考え
オブジェクトの例 人、車、黒板、机などのモノのこと。 オブジェクト指向の世界での定義→(自身の)状態に関する情報と、(自身に対する)操作を有するモノ。 例) 車 状態:型式、色、排気量、マニュアルかATか、等々。 操作:走る、停止する、等々。
(プロパティとメソッドの)カプセル化 オブジェクト→自身の状態を表すデータ+(自身に対する)操作を有するモノ データと操作の(オブジェクトへの)カプセル化 1セットにするという意味 車オブジェクト 色 排気量 走る 停止する データ プロパティ 操作 メソッド ・・・
補足 カプセル化の意味 情報の隠蔽の積極的意味 関連のあるメソッドとプロパティを組み合わせて1セットにする。 補足 カプセル化の意味 関連のあるメソッドとプロパティを組み合わせて1セットにする。 そのオブジェクトの(メソッドの)使い方以外は、情報を見せない→情報の隠蔽(データの保護という意味もある) 利用者は、オブジェクトの内部の詳細を知ることなく、オブジェクトに備わった機能(メソッド)を利用できる。 情報の隠蔽の積極的意味
オブジェクト指向的考え ある用途のためのオブジェクトがあれば・・・ そのオブジェクトのメソッドを操作することで、処理を実現 そのオブジェクトのメソッドを操作することで、処理を実現 例) ゼミでコンパを企画する。 オブジェクト→コンパ係 メソッド→企画 オブジェクト指向的記述→コンパ係.企画 (ドット記法) (意味:コンパ係に企画を依頼する。→コンパ係オブジェクトに企画せよというメッセージを送る。) プロパティとメソッドがカプセル化されたオブジェクトを用いれば、手続き型(指向)プログラミングよりも効率が上がる!? 操作(メソッド)の詳細を知る必要がない。
2.オブジェクトの基本概念 長方形オブジェクト クラスとインスタンス メソッドの継承 スーパクラスとサブクラス
長方形オブジェクト 長方形:高さと幅をプロパティとして持っている。 (ここでは)面積を求めるメソッド(操作)考える。 クラスの概念の登場 長方形A 高さ:7 幅:10 面積は? 高さ×幅 プロパティ(幅、高さ)の値によって、様々なオブジェクトがある。 幅と高さというプロパティは共通 一まとめに定義した方が便利 クラスの概念の登場
クラスとインスタンス クラス→共通の性質を持ったものの集まり 抽象化 実例 長方形クラス 長方形オブジェクト(インスタンス) 高さ: 幅: 面積は? 高さ×幅 抽象化 長方形クラス (プロパティとメソッドの定義を持つ) 長方形オブジェクト(インスタンス) 実例 長方形A 高さ:7 幅:10 長方形B 高さ:9 幅:5 ( 個々に異なるプロパティの値(のみ)を持つ ) メソッドはクラスから引き継ぐ
メソッドの継承 インスタンス(オブジェクト)がメッセージを受け取った時→自分が属するクラスのメソッドを起動する→メソッドの継承 長方形クラス 高さ: 幅: 面積は? 高さ×幅 長方形クラス 長方形オブジェクト(インスタンス) 長方形A メッセージ 面積は? 高さ:7 幅:10 面積は? 高さ×幅 70
スーパクラスとサブクラス(クラスの継承) 長方形と正方形の関係 正方形は長方形の一部→「高さ=幅」が成り立つ特別な長方形 長方形:広い範囲のインスタンスをカバーするクラス→スーパクラス 正方形:スーパクラスの一部のインスタンスのみをカバーするクラス→サブクラス
サブクラスを利用した正方形の定義 継承 長方形クラス スーパクラス 正方形クラス サブクラス 正方形オブジェクト(インスタンス) 長方形 高さ: 幅: 面積は? 高さ×幅 長方形クラス スーパクラス 継承 OMT(Object Modeling Technique)の記法 正方形 高さ=幅 正方形クラス サブクラス 正方形A 幅:10 正方形オブジェクト(インスタンス)
クラスの階層図(図形クラスの例) スーパクラスとサブクラスという概念は相対的なもの 図形 四角形 三角形 長方形 台形 正方形 サブクラス(下位のクラス)はスーパクラス(上位のクラス)の性質を全て引き継ぐ。 + 新たなプロパティあるいはメソッドを持つ。
3.オブジェクトの拡張性 ソフトウェアの生産性向上 単純なクラスに機能を付加→複雑なクラスを定義可能 既存のクラスに機能を付加→目的に応じたクラスを容易に定義できる ソフトウェアの生産性向上 オブジェクト指向プログラミングはソフトウェア危機の救世主!?
三角形クラスの定義 (多態性) 長方形クラスと三角形クラス、それぞれに異なる「面積は?」メソッドを定義 プログラムの拡張が容易に! 三角形クラスの定義 (多態性) 長方形.面積は? 図形 高さ: 幅: 長方形 面積は? 高さ×幅 三角形 高さ×幅/2 三角形.面積は? 同じ「面積は?」メッセージを受け取っても、長方形と三角形オブジェクト(インスタンス)では、振る舞いが違う。 ポリモフィズム(polymorphism:多態性) 長方形クラスと三角形クラス、それぞれに異なる「面積は?」メソッドを定義 プログラムの拡張が容易に!
デフォルトメソッドと上書き (定義の改良) デフォルトメソッドと上書き (定義の改良) 図形 高さ: 幅: 長方形 面積は? 高さ×幅 三角形 高さ×幅/2 デフォルトメソッド 多くの(しかし全てではない)インスタンスに適用できるメソッド メソッドの上書き サブクラスでメソッドを定義し直すこと <三角形クラスの異なる定義> プログラムの拡張が効率的に!
スーパ疑似変数と差分プログラム 「高さ×幅」の重複をなくす。 super:スーパ擬似変数 プログラムの拡張が効率的に! 図形 高さ: 幅: 長方形 面積は? 高さ×幅 三角形 super.面積は?/2 super:スーパ擬似変数 一つ上のクラスを表す。 拡張時にプログラムの重複を排除する上で有効 スーパクラスに何かを追加することでサブクラスのメソッドを定義する。 プログラムの拡張が効率的に! 継承を利用した差分プログラム 再利用性の向上!
理解度チェック 以下の設問に答えて下さい。 クラスとインスタンスの実例を挙げて下さい。 プログラムの再利用性を高める差分プログラムを可能にするのは、オブジェクト指向のどのような機能ですか?
クラスとインスタンス -プログラミングの場合 クラスとインスタンス -プログラミングの場合 クラス→ 型に対応 インスタンス(オブジェクト)→ 変数に対応 <通常の変数の場合> int a,b ; double x,y; <オブジェクト(インスタンス)の場合> JButton jButton1 = new JButton(); コンストラクタ JButtonクラス JButtonクラスのインスタンス
Ⅱ.オブジェクト指向の実装(Java言語の場合) <内容> フレームクラスの定義 人間クラスの定義 インスタンス(オブジェクト)の生成・利用 Java言語のメリット・デメリット
1.フレームクラスの定義(復習) <空っぽのフレームの場合> <Frame1クラスの定義> プロパティの定義 コンストラクタの定義 ・・・ } メソッドの定義 ・・・ }
フレームの生成 <Application1.javaファイル> フレームを生成する役割 frameの生成 Frame1クラスのインスタンス
インスタンスの生成(Java言語) Frame1 frame = new Frame1(); コンストラクタ クラス名 インスタンス名 クラスがあれば、インスタンス(オブジェクト)の生成は容易!
JBuilderによるJavaアプリケーションの構成 (補足) パッケージ(samplejava) <クラス> Frame1.java フレームクラスの定義 <クラス> Application1.java フレームを生成 役割分担の明確化! オブジェクト指向プログラミングの特徴
2.人間クラスの定義 サンプルプログラム 人間 動け:左右に動く 話せ:あいさつ 日本人 アメリカ人 イタリア人 話せ:こんにちは 話せ:Hello 話せ:Buon Giorno
① プログラム起動時 ③ [→]ボタンをクリックし、右へ移動 ④ [話す]ボタンをクリック ② 日本人を選択し[登場]ボタンをクリック ① プログラム起動時 ③ [→]ボタンをクリックし、右へ移動 ④ [話す]ボタンをクリック ② 日本人を選択し[登場]ボタンをクリック ⑤ [退場]ボタンをクリック
プログラムの構成 パッケージ humanmain クラスApplication1: フレームの生成 クラスFrame1: フレームの定義
人間クラスの定義 ボタンクラス(JButton)をスーパークラスに Moveメソッドの定義 Speakメソッドの定義 サブクラスを指す
人間クラスの定義(詳細) class Human extends JButton { 人間クラスの定義(詳細) class Human extends JButton { public void Move(int Dist) { Rectangle Rect; Rect=this.getBounds(); Rect.x=Rect.x+Dist; this.setBounds(Rect); } public void Speak() { this.setText("あいさつ"); 現在位置を取得 水平位置をずらす ずらした位置に表示(移動) thisはHumanクラスを指す。
日本人クラスの定義(継承) Humanクラス定義部の下に以下を追加 Humanクラスを継承 public void Speak() { class Japanese extends Human { public void Speak() { this.setText("こんにちは"); } メソッドの上書き Americanクラス、Italianクラスの定義も同様
3.インスタンスの生成・利用 Taro= new Japanese(); ① インスタンス(オブジェクト)名の宣言(Frame1クラス内) public class Frame1 extends JFrame { private Japanese Taro; private American John; private Italian Mario; ・・・ ② コンストラクタによるインスタンス生成 Taro= new Japanese(); アメリカ人およびイタリア人オブジェクト(インスタンス)の生成も同様
「登場」ボタン if(jRadioButtonJapan.isSelected()) { Taro=new Japanese(); void jButtonCreate_actionPerformed(ActionEvent e) { if(jRadioButtonJapan.isSelected()) { Taro=new Japanese(); contentPane.add(Taro); Taro.setBounds(new Rectangle(110,10,110,30)); Taro.setBackground(Color.white); Taro.setText(“Taro"); } else if(jRadioButtonAmerica.isSelected()) { ・・・ else if(jRadioButtonItaly.isSelected()) { 日本人インスタンス(Taro)を生成 x , y , w , h ボタンの大きさを設定 白色に設定 Taroと表示 アメリカ人インスタンス(John)の処理 イタリア人インスタンス(Mario)の処理
移動「→」ボタン 5歩右へ移動 if(jRadioButtonJapan.isSelected()) { Taro.Move(5); } void jButtonMoveRight_actionPerformed(ActionEvent e) { if(jRadioButtonJapan.isSelected()) { Taro.Move(5); } else if(jRadioButtonAmerica.isSelected()) { John.Move(5); else if(jRadioButtonItaly.isSelected()) { Mario.Move(5); 5歩右へ移動
「話す」ボタン 多態性の実現 if(jRadioButtonJapan.isSelected()) { Taro.Speak(); } void jButtonSpeak_actionPerformed(ActionEvent e) { if(jRadioButtonJapan.isSelected()) { Taro.Speak(); } else if(jRadioButtonAmerica.isSelected()) { John.Speak(); else if(jRadioButtonItaly.isSelected()) { Mario.Speak(); 多態性の実現
多態性のメリット(この例の場合) 日本人、アメリカ人そしてイタリア人それぞれにとって、“あいさつをする”という概念は共通。 ただ、個別的なあいさつの言葉が異なるだけ。 そこで、それら、個別の違いを気にせず、全て、Speak()というメソッドで(あいさつの表示を)実現できたら、プログラムの見通しが良く(読みやすく)、拡張も容易(ドイツ人、スペイン人クラスのインスタンスに対しても同様にプログラムできる)。 この様に、概念上同様の処理を、共通のメソッド名で表現し、処理内容の詳細がオブジェクト(インスタンス)に応じて異なっている様を多態性という。
「退場」ボタン サンプルプログラム if(jRadioButtonJapan.isSelected()) { void jButtonDelete_actionPerformed(ActionEvent e) { if(jRadioButtonJapan.isSelected()) { Taro.setVisible(false); } else if(jRadioButtonAmerica.isSelected()) { John.setVisible(false); else if(jRadioButtonItaly.isSelected()) { Mario.setVisible(false); サンプルプログラム
4.Java言語のメリット・デメリット (オブジェクト指向の観点から) オブジェクト指向プログラミングの記述が容易にできる。 オブジェクト指向の独特の記述が初心者には理解困難。 豊富なクラスライブラリが存在する。→色々な用途のアプリケーション開発が可能に。 クラスライブラリの全体像を把握する事が困難。
課題 解説で採りあげた、Java言語による人間クラスのプログラムを実際に作成して下さい。
補足) オブジェクト指向の難しさ ’90年代初頭の技術者は皆頭を悩ませた。 補足) オブジェクト指向の難しさ ’90年代初頭の技術者は皆頭を悩ませた。 オブジェクト指向の機能は便利。しかし、その活用方法のノウハウは当初は手探りだった・・・。 プログラマによってクラスの設計や継承の仕方(考え方)が異なるので、共有しにくい。 行き当たりばったりの継承が流行→スパゲッティ継承!? 現在は開発手法が整備されてきた。→クラスの設計や継承に関するルールが共有されるようになった。 きちんと教育を受ければ一定のレベルに到達するようになった。
Ⅲ.JBuilderプログラミング総復習 JBuilderを用いて行ってきたフレームの生成やイベント処理などを、(JBuilderに頼らず)最初から記述してみる。 その過程を通じてJBuilderの機能のメリットを理解する。 <内容> mainクラスの定義 フレームの生成 mainクラスとフレームクラスの役割分担 ボタンとテキストフィールドの貼り付け イベント処理の実装① イベント処理の実装②
1.mainクラスの定義 コンストラクタ省略可 mainメソッドの定義:一つの処理に対し必ず一つ定義する。 class FrameApplication { public FrameApplication() { } public static void main(String[] args) { System.out.println("実行成功!"); コンストラクタ省略可 mainメソッドの定義:一つの処理に対し必ず一つ定義する。 FrameApplication.javaとして保存 以下、作成したファイルやフォルダが、javac.exeやjava.exeなどのJava翻訳システムがあるフォルダにあるものとして話を進める。
mainクラスの翻訳・実行 ① バイトコードへの変換(翻訳) ② バイトコードの実行 実行結果!
2.フレームの生成 フレームクラスはjavax.swingパッケージにある import javax.swing.*; class FrameApplication { public static void main(String[] args) { JFrame frame=new JFrame(); frame.setSize(300,200); frame.setTitle("自作のフレーム"); frame.setLocation(100,50); frame.setVisible(true); } フレームオブジェクトの生成 フレームの幅wと高さhを設定 w h 表示位置(x,y)の設定 x y フレームを表示させる
フレームの生成→実行 200 300 プログラムの終了処理を記述しなければならない。 50 100 ※ ×をクリックしても、ウィンドウは閉じるがプログラムの実行は終了しない。 プログラムの終了処理を記述しなければならない。
3.mainクラスとフレームクラスの役割分担 <準備> 適当なフォルダ、例えばframesampleというフォルダを作る。 その中にFrameApplication.javaを移動する。 同フォルダ内に、フレームを定義するFrame1.javaを作る。 framesample FrameApplication.java Frame1.java パッケージ フレームを生成・表示 フレームを定義 ここで新たに定義
Frame1.java JFrameを継承 パッケージの指定 package framesample; import javax.swing.*; import java.awt.event.*; class Frame1 extends JFrame { public Frame1() { ・・・ } //ウィンドウが閉じられたときに終了するようにオーバーライド protected void processWindowEvent(WindowEvent e) { ウィンドウ(フレーム)の終了処理のために必要 JFrameを継承 コンストラクタ フレームの初期処理
FrameApplication.java 役割分担の徹底 JBuilderで皆が意識しなかった理由 package framesample; class FrameApplication { public static void main(String[] args) { Frame1 frame=new Frame1(); frame.setLocation(100,50); frame.setVisible(true); } フレームオブジェクトの生成 役割分担の徹底 これで、FrameApplication.javaは(フレーム設計を変えても)いじる(変更する)必要がなくなる。 JBuilderで皆が意識しなかった理由
4.ボタンとテキストフィールドの貼り付け <Frame1.java> class Frame1 extends JFrame { private JPanel contentPane; private JTextField TField1 = new JTextField(); private JButton Btn1= new JButton(); public Frame1() { contentPane = (JPanel) this.getContentPane(); contentPane.setLayout(null); TField1.setBounds(20,10,200,25); contentPane.add(TField1); Btn1.setBounds(20,60,120,25); Btn1.setText("自作ボタン"); contentPane.add(Btn1); this.setSize(300,200); this.setTitle("自作のフレーム"); } テキストフィールドの貼り付け ボタンの貼り付け
5.イベント処理の実装① イベントリスナの登録 メソッドの上書き(定義) ボタンをクリックした時に、テキストフィールドに「イベント処理成功!」という文字を表示させるには・・・ 以下の部分を加える。 イベントリスナの登録 public Frame1() { ・・・ this.setTitle("自作のフレーム"); Btn1.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { TField1.setText("イベント処理成功!"); } }); リスナインタフェース メソッドの上書き(定義)
6.イベント処理の実装② 皆がいつも記述していた部分 メソッドに置き換える public Frame1() { ・・・ this.setTitle("自作のフレーム"); Btn1.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { TField1.setText("イベント処理成功!"); } }); Btn1_actionperformed(); メソッドに置き換える public void Btn1_actionperformed() { TField1.setText("イベント処理成功!"); } 皆がいつも記述していた部分
JBuilderを用いると・・・ パッケージ プログラマは・・・ Frame1.javaに於いて Application1.java Frame1.java プログラマは・・・ Frame1.javaに於いて フレームの設計(ボタンやテキストフィールドなどの貼り付け等)とイベント処理プログラム(ボタンクリック時のプログラム等)の記述に専念できる。 フレームを生成するApplication1.javaというプログラムはいじる(変更する)必要がない。 クラス間の役割分担の徹底により、効率よくプログラムを作成できる様になっている。
課題 本日は、オブジェクト指向の基礎概念とJava言語におけるオブジェクトプログラミングを学習しました。この学習内容の感想を、良く理解できた点と理解が困難だった点を含めて述べて下さい。
Java言語におけるクラスの定義 class クラス名 { プロパティ(フィールド)の定義 コンストラクタの定義(初期化処理) コンストラクタの定義(初期化処理) メソッドの定義 }
クラスの継承 スーパークラス サブクラス public class Frame1 extends JFrame { プロパティの定義 プロパティの定義 コンストラクタの定義 メソッドの定義 } 全クラスから参照可能 コンポーネントはオブジェクト
復習)デフォルトメソッドと上書き (定義の改良) 復習)デフォルトメソッドと上書き (定義の改良) 図形 高さ: 幅: 長方形 面積は? 高さ×幅 三角形 高さ×幅/2 デフォルトメソッド 多くの(しかし全てではない)インスタンスに適用できるメソッド メソッドの上書き サブクラスでメソッドを定義し直すこと <三角形クラスの異なる定義> プログラムの拡張が効率的に!
人間クラスの継承図 スーパークラス サブクラス Taro John Mario インスタンス 人間 Move:左右に動く Speak:あいさつ サブクラス 日本人 アメリカ人 イタリア人 Speak:こんにちは Speak:Hello Speak:Buon Giorno Taro John Mario インスタンス
復習) 多態性(図形クラスの定義より) ポリモフィズム(polymorphism:多態性) 復習) 多態性(図形クラスの定義より) 長方形.面積は? 図形 高さ: 幅: 長方形 面積は? 高さ×幅 三角形 高さ×幅/2 三角形.面積は? 同じ「面積は?」メッセージを受け取っても、長方形と三角形オブジェクト(インスタンス)では、振る舞いが違う。 ポリモフィズム(polymorphism:多態性) 長方形クラスと三角形クラス、それぞれに異なる「面積は?」メソッドを定義 プログラムの拡張が容易に!
参考:言語の制約の度合い BASIC C 制約大 Java print “Hello!” 行が基本 main( ) { printf(“Hello!\n"); } C 関数が基本 public class Hello { public static void main(String args[ ]) { System.out.println(“Hello!”); } Java クラスが基本
一般に・・・ 一般に、オブジェクト指向言語は最も記述に手間がかかる。 ただ、プログラムの再利用性と見通しの良さは最も良い。 オブジェクト指向言語が威力を発揮するのは、大きなプログラムを共同で開発する時。
コンストラクタの記述 コンストラクタはインスタンス(オブジェクト)が生成される時に呼び出される特別なメソッド class Frame1 extends JFrame { public Frame1() { this.setSize(300,200); this.setTitle("自作のフレーム"); } ・・・ これにより、フレームが生成されるときに、その大きさとフレームタイトルが設定される。 コンストラクタはインスタンス(オブジェクト)が生成される時に呼び出される特別なメソッド
フレームの終了処理 ×を選択した場合 メソッドの上書き→終了処理を加える。 プログラムを終了させる。 //ウィンドウが閉じられたときに終了するようにオーバーライド protected void processWindowEvent(WindowEvent e) { if (e.getID() == WindowEvent.WINDOW_CLOSING) { System.exit(0); } ×を選択した場合 プログラムを終了させる。 メソッドの上書き→終了処理を加える。