比較プログラム言語論

オブジェクト指向基礎学習Ⅰ
~オブジェクト指向へ至る背景~
平成19年6月13日
森田 彦
学習内容
プログラミング言語教養編
I.
II.
最も早く普及した言語「FORTRAN」発展の経
緯
構造化プログラミングの提唱
Ⅰ.最も早く普及した言語「FORTRAN」発展の
経緯
<内容>



FORTRANの起源および発展の概観
分岐処理の記述の発展
繰り返し処理の記述の発展
<学習する理由>
古い言語の発展の経緯を知ることで、オブジェクト指向プログ
ラミングが生まれた背景を理解できるようになるから。
FORTRANの起源





1954年、IBM社バッカス(Backus)らにより開発開始:ソ
フトウェア開発のコストが急増→使いやすい高水準プロ
グラミング言語の必要性
1957年 IBM社の汎用大型コンピュータIBM704のプロ
グラム処理言語として実装
当初はIBM Mathematical FORmula TRANslating
System と命名 →FORTRAN
その性能や設計内容が高く評価される。
科学技術計算に適している。
発表後、FORTRANは進化し続けている。
その進化の方向性に注目!
FORTRANの発展①
原型 ー 型宣言のない世界
<プログラム例>
1234567890
プログラムは7~72列の間に記述する。
----------------------------------------<実行結果>
A=3.5
12345678901
B=1.5
-------------------------J=(A+B)/2
3. 5 1. 5 2
WRITE(6,100) A,B,J
100 FORMAT(2F4.1,I3)
I,J,K,・・・,Nで始まる変数:整数型
STOP
それ以外
:実数型
END
きわめて簡単な文法規則! 数式を書く様にプログラムを
書ける!
FORTRANの発展②
副プログラムの導入

1958年FORTRANⅡ発表→副プログラム(サブ
ルーチン)の導入
1234567890
----------------------------------------------
A=3.5
B=1.5
CALL HEIKIN(A,B,C)
WRITE(6,100) A,B,C
100 FORMAT(2F4.1,F5.2)
STOP
END
SUBROUTINE HEIKIN(A,B,C)
C=(A+B)/2
RETURN
END
<実行結果>
1234567890123
-------------------------3. 5 1. 5
2. 5
プログラムの見通しが良くなる。
FORTRANの発展③
型宣言の導入

1962年、FORTRANⅣ発表→型宣言を導入
1234567890
--------------------------------------------
REAL A,B
INTEGER J
A=3.5
B=1.5
J=(A+B)/2
WRITE(6,100) A,B,J
100 FORMAT(2F4.1,I3)
STOP
END
ALGOL60プロジェクトの影響
1234567890
------------------------------------------
A=3.5
これもOK
B=1.5
J=(A+B)/2
WRITE(6,100) A,B,J
100 FORMAT(2F4.1,I3)
STOP
END
<暗黙の型宣言>
I,J,K,・・・,Nで始まる変数:整数型
それ以外
:実数型
FORTRANの発展④
文字列型の導入

1978年、FORTRAN77発表→文字列型の導入
1234567890
--------------------------------------------
REAL A,B
INTEGER J
CHARACTER MOJI*7
MOJI=‘Result:’
A=3.5
B=1.5
J=(A+B)/2
WRITE(6,100) MOJI,A,B,J
100 FORMAT(A,2F4.1,I3)
STOP
END
<実行結果>
1234567890123456789
-------------------------------Result : 3. 5 1. 5
2
分岐処理の記述の発展①
分岐処理の表現(初期)
テストの得点を入力し、50点以上な
ら「合格」、50点未満なら「不合格」と
表示するプログラム
始め
Tenの入力
Ten≧50
No
Yes
‘合格’と表示
終り
‘不合格’と表示
IF と GO TO の世界
INTEGER TEN
READ(5,*) TEN
IF(TEN.GE.50) GO TO 10
WRITE(6,*) ‘不合格’
GO TO 20
10 WRITE(6,*) ‘合格’
20 STOP
END
プログラムの見通しが良くない!
分岐処理の記述の発展②
分岐処理の表現(改良)
テストの得点を入力し、50点以上な
ら「合格」、50点未満なら「不合格」と
表示するプログラム
始め
Tenの入力
Ten≧50
No
Yes
‘合格’と表示
終り
‘不合格’と表示
IF THEN~ ELSE~ END IF 文
の導入
INTEGER TEN
READ(5,*) TEN
IF(TEN.GE.50) THEN
WRITE(6,*) ‘合格’
ELSE
WRITE(6,*) ‘不合格’
END IF
STOP
END
無駄な文番号を排除→ GO TO文を排除
多分岐処理の記述 発展(CASE文)
select case (N)
case (0)
N=0の場合の処理
case (1:49)
1≦N≦49の場合の処理
case (50:79)
50≦N≦79の場合の処理
case default
上記以外の場合の処理
end select
無駄な文番号がな
くなり見通しが良く
なった。
FORTRAN90で導入
繰り返し処理の記述の発展①
繰り返し処理の表現(初期)
1~Nまでの和を求める。
始め
Nの入力
SUM←0
I←1
I≦N
Yes
SUM←SUM+i
i ← i+1
No
終り
IF と GO TO の世界
INTEGER N,SUM,I
READ(5,*) N
SUM=0
I=1
10 CONTINUE
IF(I.GT.N) GO TO 20
SUM=SUM+I
I=I+1
GO TO 10
20 CONTINUE
STOP
END
プログラムの見通しが良くない
繰り返し処理の記述の発展②
繰り返し処理の表現(改良)
1~Nまでの和を求める。
DO文 の導入
INTEGER N,SUM,I
READ(5,*) N
SUM=0
DO 10 I=1,N
SUM=SUM+I
10 CONTINUE
STOP
END
始め
Nの入力
SUM←0
I←1
I≦N
Yes
SUM←SUM+i
i ← i+1
No
終り
さらに・・・
INTEGER N,SUM,I
READ(5,*) N
SUM=0
DO I=1,N
SUM=SUM+I
END DO
STOP
END
DO文の導入→GO TO文の排除
プログラムの見通しが良くなる
DO WHILE文の導入
例)SUM=1+2+・・・を、SUMが100を超えるまで繰り返す。
INTEGER SUM,I
SUM=0
I=0
DO WHILE(SUM<=100)
I=I+1
SUM=SUM+I
END DO
Java言語のwhile文と同
等!
FORTRAN90で導入
その後FORTRAN95を発表→進化し続けている。
Ⅱ.構造化プログラミングの提唱






提唱の背景-GOTO文の魔力
ダイクストラの主張
構造化のメリット
言語仕様への影響
プログラムのモジュール化へ
ソフトウェア危機
GOTO文の魔力
2.処理Bの前にCが必要に
→処理Cを挿入
1.処理A,Bの実行
処理A
処理A
処理C
処理B
GOTO文を用いると・・・
処理B
当時の編集
環境では手
間がかかる。
3.完成
処理A
処理C
処理B
処理A
処理B
作成時の順番を維持できる→(当
時としては)開発効率が上がる。
しかし、読みにくい。→ミスを誘発する。
処理C
処理の順番通りに記述した方が読みや
すい。
スパゲッティ・プログラム(BASICの例)
10: INPUT A
10: INPUT A
20: IF A>0 THEN 50
20: IF A>0 THEN 50
30: PRINT “正ではない”
25: IF A=0 THEN 45
40: GOTO 60
30: PRINT “負の数”
50: PRINT “正の数”
40: GOTO 60
60: END
45: PRINT “0である”
思いつくままに、GOTO文を
使ってプログラムを拡張。→
迷路のようなプログラムに。
46: GOTO 60
50: PRINT “正の数”
60: END
ダイクストラの主張
構造化定理:1つの入り口と1つの出口を持つよう
なアルゴリズムは、「連接」、「分岐」、「繰り返し」
の基本構造を(処理の順に)つなげることで記述
できる。→ダイクストラが証明
 あらゆる処理(アルゴリズム)はGOTO文なしに
記述可能。
→ 1968年 Dijkstraが主張。→構造化プログラミ
ング(運動)の始まり。

分かりやすいプログラムを書こう!
構造化プログラミングのメリット




処理の順番に記述されるので、プログラムが読
みやすい。
フローチャートによるプログラム設計が可能
バグの少ないプログラムの開発が可能
構造化により、無駄な処理が少なくなる。
プログラム開発の効率が向上する。
言語仕様への影響




プログラミング言語は、連接、分岐、繰り返しを表現する機能
がなければならない。
C:条件 S:処理 と表すと・・・
分岐の表現
if C then S1 else S2
多分岐
case C of (C1:S1;C2:S2;・・・Cn:Sn)
繰り返しの表現
while C do S (for文はカウンタ変数を用いる特殊な用途
のために特別に用意。全ての処理はwhile文で記述可能)
これらの機能が備わって行く過程は、FORTRANの発展過
程に顕著。
プログラムのモジュール化





構造化プログラミング→プログラムを基本構造(連接・分
岐・反復)を(処理の順に)つなげて表現する。
幾つかの基本構造→ひとまとまりの処理→モジュール
モジュール→ サブルーチン(FORTRAN)、関数(C言
語)など。
プログラムはモジュールの組み合わせで表現できる。
プログラムの基本構造は、モジュールを(処理の順に)
つなげて表現できる。個々の処理の詳細はモジュール
内部で記述。
構造化プログラミングの最終的な主張。
プログラムのモジュール化 例
問題 学生のテスト成績を読み込み成績順に表示する。
<プログラムの構造>
データの読み込み
データのソート
データの表示
<メインルーチン>
Integer Tokuten(200)
CALL ReadData(Tokuten)
CALL SORT(Tokuten)
CALL Display(Tokuten)
<ポイント>
プログラムの基本構造はメインルーチンで記述
処理の詳細はモジュール(サブルーチン)で記述
プログラムの基本構造が分かりやすくなる。
→見通しが良くなる。
モジュール化に基づく構造化プログラミングの
工程
1. 要求される処理を幾つかの処理(モジュール)に分割
2. モジュールの命名
3. モジュールを適切な順に配置
4. 各モジュールの処理内容の記述
全体
トップダウン的思考が必要!
部分
参考) モジュール化に基づく構造化プログラ
ミングの例
カレンダープログラム:日付を入力すると、それが何曜日かを表示。
メインプログラム
void jButton1_actionPerformed(ActionEvent e) {
int Year=Integer.parseInt(jTextFieldY.getText());
int Month=Integer.parseInt(jTextFieldM.getText());
int Day=Integer.parseInt(jTextFieldD.getText());
String Youbi;
Youbi=YoubiCalc(Year,Month,Day); //曜日を求める
jLabelAns.setText(Youbi+“です。”); //結果表示
}
年月日を与えると曜日を計算してくれるモジュール(メソッ
ド)を定義
YoubiCalc(Year,Month,Day)メソッド
String YoubiCalc(int Year, int Month, int Day) {
String WDay;
int N= DayCount(Year,Month,Day) % 7;
switch (N) {
case 0:
曜日はある基準日(例え
WDay="日曜日";
ば2000年12月31日:日曜
break;
case 1:
日)からの日数で決まる。
WDay="月曜日";
break;
・・・
}
return WDay;
}
年月日を与えると基準日からの日数を計算するモジュー
ル(メソッド)を定義
DayCount(Year,Month,Day)メソッド
int DayCount(int Year,int Month,int Day) {
int DaySum=0;
for (int i=2001;i<Year;i++) {//1年前の12/31までの日数
if( Uruu(i) ) {
DaySum=DaySum+366;
閏年を判定する必要が
} else{
ある。
DaySum=DaySum+365;
}
}
for (int i=1;i<Month;i++) { //一月前の月末までの日数
・・・
}
DaySum=DaySum+Day; //当該月の日数を加える
return DaySum;
}
当該年が閏年かどうかを判定するモジュール(メソッド)を
定義
以上を振り返ると・・・
メインプログラム
YoubiCalc(Year,Month,Day)メソッドの定義
DayCount(Year,Month,Day)メソッドの定義
Uruu(Year)メソッド の定義
プログラムの完成!
読みやすさ / 書きやすさの視点から構造化プ
ログラミングを見ると・・・




「IF+GO TO」文の世界→思いつくままに記述できる。→書き
やすい(特別な訓練なしでも書ける)。
しかし、後から見ると読みにくい。→開発効率に限界
一方、構造化プログラミングの世界では・・・
基本構造さらにはモジュールの組み合わせで(処理順に)記
述する。→記述する際にプログラムの全体構造を把握して
おく必要がある。→慣れるまで訓練(教育)が必要。
出来上がったプログラムは読みやすい。→開発効率は上が
る。
構造化プログラミングの普及→教育の必要性増大
書きやすさから読みやすさへ
ソフトウェア危機





構造化プログラミング→ソフトウェアの生産性向上
しかし、既存のソフトウェアの再利用性については十分
な向上が得られなかった。
ソフトウェアの需要増に、ソフトウェアの生産が追いつか
ない→ソフトウェア危機
特に、GUI環境の普及に伴って、その傾向が顕著に!
「使う方は天国、作る方は地獄」
より効率の良い、プログラム開発形態は?→オブジェク
ト志向プログラミングが注目される。
プログラムの拡張の容易さ、あるいは再利用性の向上(差分プ
ログラムの徹底)がキーポイント!
オブジェクト指向言語でどのように改善されるか?
Ⅲ.オブジェクト指向の考え方
オブジェクト指向の考えのエッセンスを学習し、それをプログ
ラム開発に応用した場合にどのようなメリットがあるかを理
解する。
<内容>



1 オブジェクトとは何か?
2 オブジェクトの基本概念
3 オブジェクトの拡張
1.オブジェクトとは何か?



オブジェクトの例
カプセル化(プロパティとメソッド)
オブジェクト指向的考え
オブジェクトの例
人、車、黒板、机などのモノのこと。
 オブジェクト指向の世界での定義→(自身の)状
態に関する情報と、(自身に対する)操作を有す
るモノ。
 例) 車
状態:型式、色、排気量、マニュアルかATか、
等々。
操作:走る、停止する、等々。

(プロパティとメソッドの)カプセル化


オブジェクト→自身の状態を表すデータ+(自身
に対する)操作を有するモノ
データと操作の(オブジェクトへの)カプセル化
1セットにするという意味
車オブジェクト
色
走る
停止する
排気量
データ
・・・
操作
・・・
プロパティ
メソッド
補足 カプセル化の意味


関連のあるメソッドとプロパティを組み合わせて1セット
にする。
そのオブジェクトの(メソッドの)使い方以外は、情報を見
せない→情報の隠蔽(データの保護という意味もある)
利用者は、オブジェクトの内部の詳細を知ることなく、オブ
ジェクトに備わった機能(メソッド)を利用できる。
オブジェクト指向的考え

ある用途のためのオブジェクトがあれば・・・
そのオブジェクトのメソッドを操作することで、処理を実現

例) ゼミでコンパを企画する。
オブジェクト→コンパ係 メソッド→企画
オブジェクト指向的記述→コンパ係.企画 (ドット記法)
(意味:コンパ係に企画を依頼する。→コンパ係オブジェクトに
企画せよというメッセージを送る。)

プロパティとメソッドがカプセル化されたオブジェクト
を用いれば、手続き型(指向)プログラミングよりも
効率が上がる!?
操作(メソッド)の詳細を知る必要がない。
2.オブジェクトの基本概念




長方形オブジェクト
クラスとインスタンス
メソッドの継承
スーパクラスとサブクラス
長方形オブジェクト


長方形:高さと幅をプロパティとして持っている。
(ここでは)面積を求めるメソッド(操作)考える。
長方形オブジェクト
長方形A
高さ:7
面積は?
プロパティ(幅、高さ)の値によって、
様々なオブジェクトがある。
幅:10
幅と高さというプロパティは共通
高さ×幅
一まとめに定義した方が便利
クラスの概念の登場
クラスとインスタンス

クラス→共通の性質を持ったものの集まり
長方形
高さ:
長方形クラス
幅:
抽象化
(プロパティとメソッドの定義を持つ)
面積は?
高さ×幅
長方形A
長方形B
高さ:7 幅:10
高さ:9 幅:5
長方形オブジェクト
実例
(インスタンス)
( 個々に異なるプロパティの
値(のみ)を持つ )
メソッドはクラスから引き継ぐ
メソッドの継承

インスタンス(オブジェクト)がメッセージを受け
取った時→自分が属するクラスのメソッドを起動
する→メソッドの継承
長方形オブジェクト
(インスタンス)
長方形クラス
長方形A
メッセージ
面積は?
70
高さ:7 幅:10
面積は?
高さ×幅
長方形
高さ:
面積は?
高さ×幅
幅:
スーパクラスとサブクラス(クラスの継
承)
長方形と正方形の関係
正方形は長方形の一部→「高さ=幅」が成り立
つ特別な長方形
 長方形:広い範囲のインスタンスをカバーするク
ラス→スーパクラス
 正方形:スーパクラスの一部のインスタンスのみ
をカバーするクラス→サブクラス

サブクラスを利用した正方形の定義
長方形
高さ:
幅:
面積は?
高さ×幅
長方形クラス
スーパクラス
継承
OMT(Object Modeling Technique)の記法
正方形
高さ=幅
正方形A
幅:10
正方形クラス
サブクラス
正方形オブジェクト
(インスタンス)
クラスの階層図(図形クラスの例)
図形
四角形
長方形
正方形
三角形
台形
スーパクラスとサブクラスと
いう概念は相対的なもの
サブクラス(下位のクラス)はスーパクラス(上
位のクラス)の性質を全て引き継ぐ。 +
新たなプロパティあるいはメソッドを持つ。
3.オブジェクトの拡張性


単純なクラスに機能を付加→複雑なクラスを定
義可能
既存のクラスに機能を付加→目的に応じたクラ
スを容易に定義できる
ソフトウェアの生産性向上
オブジェクト指向プログラミングはソフトウェア危機の
救世主!?
三角形クラスの定義 (多態性)
長方形.面積は?
図形
高さ:
長方形
面積は?
高さ×幅
三角形.面積は?
幅:
三角形
面積は?
高さ×幅/2
長方形クラスと三角形クラス、それぞれ
に異なる「面積は?」メソッドを定義
同じ「面積は?」メッセージを受
け取っても、長方形と三角形オ
ブジェクト(インスタンス)では、
振る舞いが違う。
ポリモフィズム
(polymorphism:多態性)
プログラムの拡張が
容易に!
デフォルトメソッドと上書き (定義の改良)
図形
高さ:
デフォルトメソッド
幅:
多くの(しかし全てではない)イン
スタンスに適用できるメソッド
面積は?
高さ×幅
メソッドの上書き
長方形
三角形
面積は?
高さ×幅/2
<三角形クラスの異なる定義>
サブクラスでメソッドを定義し
直すこと
プログラムの拡張が効率的に!
スーパ疑似変数と差分プログラム
「高さ×幅」の重複をなくす。
図形
高さ:
幅:
super:スーパ擬似変数
面積は?
高さ×幅
一つ上のクラスを表す。
拡張時にプログラムの重複
を排除する上で有効
長方形
三角形
面積は?
super.面積は?/2
スーパクラスに何かを追加することでサブクラスのメソッドを定義する。
継承を利用した差分プログラム プログラムの拡張が効率的に!
再利用性の向上!
考察課題
以下の設問に答えて下さい。
1. クラスとインスタンスの実例を挙げて下さい。
2. プログラムの再利用性を高める差分プログラムを
可能にするのは、オブジェクト指向のどのような機
能ですか?
プログラムのモジュール化 例
問題 学生のテスト成績を読み込み成績順に表示する。
<プログラムの構造>
データの読み込み
データのソート
データの表示
<メインルーチン>
Integer Tokuten(200)
CALL ReadData(Tokuten)
CALL SORT(Tokuten)
CALL Display(Tokuten)
<ポイント>
プログラムの基本構造はメインルーチンで記述
処理の詳細はモジュール(サブルーチン)で記述
プログラムの基本構造が分かりやすくなる。
→見通しが良くなる。
モジュールの再利用(問題点)
問題 学生のテスト成績を読み込み成績順に表示する。
テストの得点だけではなく、学生の氏名も読み込むように拡
張すると・・・。
 修正に手間がかかる。
Integer Tokuten(200)
 既存部分はいじらず、新たに必要になっ
た部分のみを加えるような修正はできない
か→差分プログラムの徹底
Character Shimei(200)
CALL ReadData(Tokuten,Shimei)
CALL SORT(Tokuten,Shimei)
CALL Display(Tokuten,Shimei)
サブルーチンの書き直しが
必要
サブルーチン内部の理解
が必要
FORTRAN用パンチカード
1
2

穴の開いている位置で、英数字などの記号を表現。
 カード1枚が1行に対応。
プログラム(アルゴリズム)の基本構造
連接
処理A
処理B
処理C
処理A,B,Cを
順に処理
分岐
条件
繰り返し
No
条件
Yes
処理A
処理B
条件が成立すれば処
理A、そうでなければ
処理Bを実行
No
Yes
処理A
条件が成立している間は、
処理Aを繰り返し実行