クラス

2004/11/23
オブジェクト指向プログラミング − モデル図とシーケンス図の表現方法 −
オブジェクト指向プログラミング(OOP:Object Oriented Programing)
オブジェクト指向プログラミング言語(OOPL)
→ Java , C++ , Delphi (Pascal), Visual Basic, smalltalk, Simulla
オブジェクト指向ソフトウエア開発(システム開発)
※システム(プログラム)の開発,構築の方法 (①∼③の手順に従う)
(オペレーティングシステム,在庫管理システム,自動販売機,成績管理システムなど)
①分析:(概念レベルでの機能要件および機能実施方法の整理)
②設計:(実装を意識した詳細な設計とまとめ)
③実装:(プログラミング)
オブジェクト指向に基づく分析,設計およびプログラミングを行う場合には“クラス”の利用が必須となる.
“クラス“ とは、




OOPL で用いられる自分で作成できる‘型’(プログラマが自由に作成できる)
利用方法は C 言語の構造体に類似する
(構造体に比べて)変数だけでなく関数も利用できる
OOPL の中心的役割
“クラス”は ‘型’ なので、具体的な ‘実体’ が作成される
この‘実体’を “オブジェクト”,“インスタンス”、“実体” と呼ぶ
“クラス”と“オブジェクト”の相違(“オブジェクト”の方から見ると…)
オブジェクト: 現実世界に存在する具体的なもの
状態(属性)、振る舞い(操作)、識別子を持つ
(オブジェクトの状態とは、そのオブジェクトが取り得る状況を指定したものを指す。
振る舞いとはオブジェクトの取る行動,他のオブジェクトからの要求に対する反応)
クラス :
共通の構造や振る舞いを持ったオブジェクトの集合を抽象的な表現で定義したもの
(例)
(例)
クラス
抽象概念
人間
科目
オブジェクト
具体例
田中さん, 山田さん
英語,数学
プログラムで考えると
class Seiseki{
int math;
int eng;
int sci;
1 人分の成績を
//-- 数学の成績
//-- 英語の成績
//-- 科学の成績
格納するためのデータ構造体
抽象的(一般的)な表現
}

クラス
上記のクラスがプログラムで利用される場合,田中さん,山田さんのデータを格納するためには次のように表現され
る.
−1−
2004/11/23
Seiseki
tanaka, yamada;
田中さん用, 山田さん用 のデータ領域がメモリ上に用意される.
具体的な人に対して設定されたデータ構造
→ オブジェクト に対応
math
eng
sci
math
eng
sci
○クラスの表現方法(図の書き方)
・ 日本語を利用して理解しやすいようにする
クラス名
変数
<属性>
メソッド(関数)
<操作>
オブジェクト,インスタンス(実態)
氏名
文字列
文字列の長さ
クラスの記述方法
文字列設定
文字列取得
文字列表示
文字列クラス
文字列
文字列の長さ
文字列設定
文字列取得
文字列表示
住所
文字列
文字列の長さ
文字列設定
文字列取得
文字列表示
クラス (型)
プログラム上でのクラスの記述方法(例)
class
クラス名 {
private 型 変数;
public 型 メソッド{
//
//
//
private : そのクラス自身からのみアクセス可能
public
: 全てのクライアントからアクセス可能
protected : 全てのサブクラスからだけアクセス可能
}
}
プログラム作成の違い
プログラムの作成方法は次の2種類に分けられる
「手続きを中心」 , 「データ(オブジェクト)を中心」
(1) 「手続きを中心とするプログラム作成」とは
(C 言語など)
関数(メソッド)を多数作成し、必要に合わせて関数を選択し、利用する。
データを手続き(関数)に渡す。 (データと手続きは独立として扱う)
→ 同様に類似するが詳細には異なる関数が多数作成される
(関数名が冗長となり、一つのファイルに類似するが関連性のない関数が乱雑する)
(2) 「データを中心とするプログラム作成」とは
(Java,C++言語など オブジェクト指向言語)
データに依存する処理の手続きを作成し,データから手続きを行う。(手続きはデータに含まれる)
−2−
2004/11/23
(手順)
① 処理内容 → データに渡す
(データはクラス(プログラム上はオブジェクト)が対応する)
② データ(クラス)内に定義された手続き(メンバ関数)を実行
複数のクラス間の関係
関係は大きく分類すると3つある
 関連 :
クラスとクラス間の一方向あるいは双方向の意味的な接続(情報を送る、受け取るなど)
 集約 :
関連の一種であり、全体とその部分との関係をあらわす
 汎化,継承 : 継承構造を定義する関係 (子クラスは親クラスの属性、操作をすべて受け継ぐ)
クラス A
クラス C
関連
(全体)
(親クラス)
[super クラス]
集約
汎化, 継承
クラス B
クラス D
(子クラス)
[sub クラス]
(部分)
(例 )
集約
チョコレート
注文 A
食パン
キャンディ
注文
注文商品
汎化
コイン
お金
(属性) 数,合計金額
紙幣
(操作) 金額の加算
(属性) 数,合計金額
(操作) 金額の加算
継承について
複数のクラスの内部構造が類似する(あるいは部分的に一致する)ならば類似する部分を共有化することができる
→ 継承の適用 (汎化)
多角形
新しい点の設定( )
点の移動( )
親クラス
(共通部分)
三角形
四角形
3点数の座標
4点数の座標
子クラス
(共通部分以外を実装)
−3−
2004/11/23
プログラム上の継承の記述方法
クラス B
親クラス
クラス D
子クラス
// 親クラス
class クラス B{
// この内部は通常のクラスと同様
}
// 子クラス
class クラス D extends クラス B{
// この内部はクラス D のみで
// 利用するものを記述する
}
隠蔽処理
クラス内のメンバ(変数,関数。特に変数に適用される)を外部(別のクラスからの操作やプログラム)から、操作され
ないようにすること.
操作されたくないメンバを private にし, public のメソッド(関数)を利用して外部からそのメンバを操作する.
(例) メンバ変数 x、y を隠蔽したい場合
Class
Point {
private double x, y;
public void set(double, double) {
x= ix;
y= iy;
}
//--- この関数によって座標の設定操作を行う
}
クラス間の関係の実装方法 (関連,集約,汎化(継承))
① 関連
クラス間で情報のやり取りがある場合の関係
(基本的には,情報が双方向に送られることを仮定)
※ 参照可能性 : クラス間で他のクラスを(単方向に)参照できること
← クラス間の情報の移動は単方向の場合が多い
“関連を実装する”
―→
―→
“相手のオブジェクトを操作できるようにする”こと
“クラスのメンバに相手のクラスのオブジェクトを持つ”ことになる
クラス A
関連
クラス C
「クラス A」は「クラス C」を参照できる。
(「クラス A」が「クラス C」の関数を利用する場合)
「クラス C」は「クラス A」を参照できない。
※ 双方向の参照可能性は 単方向の拡張で扱える。
−4−
2004/11/23
プログラム例
(1)関連先が単数の場合 (クラス C の実体が単数の場合)
class Class_C {
// クラス C の定義
……
}
class Class_A {
// クラス A の定義
……
Class_C Item; // クラス C のオブジェクト ←― A の操作内で C の操作が可能である
……
→ C の操作を持つ
}
(このあと,ClassC のコンストラクタにより
オブジェクトを作成する)
(2)関連先が複数の場合 (クラス C の実体が複数の場合)
class Class_C {
// クラス C の定義
……
}
class Class_A {
// クラス A の定義
……
Class_C Item1, Item2;
←― クラス C の複数のオブジェクトを持つ
……
}
② 集約
クラス間における “全体と部分” の関係
クラス A
集約
クラス B
「クラス A」は“全体” , 「クラス B」は “部分”
“集約を実装する”
―→
“クラスのメンバに相手のクラスのオブジェクト(実体)を持つ” ことになる
(主に,配列が実装される)
プログラム例
class Class_B {
// クラス B の定義
……
}
class Class_A {
// クラス A の定義
……
Class_B Item[100]; // クラス B のオブジェクト
……
}
←― クラス B のオブジェクトを設定
Class_A のオブジェクトが 1つ作成されるごとに Class_B のオブジェクトが 100 作成される
→ 上のプログラムの場合 Class_A のオブジェクトが削除されれば,Class_B の 100 のオブジェクトも削除される
−5−
2004/11/23
③ 汎化 (継承)
クラス C
汎化,継承
クラス D
「クラス C」は“スーパークラス(親クラス)”
「クラス D」は“サブクラス(子クラス)”
「クラス D」は「クラス C」の性質(属性,操作)を受け継ぐ
プログラム例
class Class_C {
// クラス C の定義
int age;
String name;
void setname(String name);
}
class Class_D extends Class_C { // クラス D の定義
int adress;
}
←― 通常のクラスの記述
←― クラス D では 1行のみ設定されているが,
親クラスの int age,String name,
void setname( ) も組込まれている
※ 親クラスと子クラスが同一のメソッド(操作)を有する場合
→ 子クラスから親クラスのメソッドを呼ぶ出す場合,
“ super.メソッド名(
) ”を利用する
クラス図とシーケンス図
オブジェクト指向に基づきプログラムの開発を行う場合では,これまでの手続き型のプログラム作成で持ちられて
きた PDL やフローチャートはほとんど利用されない。
プログラムや処理の流れを表現する記述方法(図)として、いくつかの図が提案されている。
(これらの図は規格化されており,まとめて UML (Unified Modeling Language) と呼ばれている。)
ここではその中でも特に重要なクラス図とシーケンス図について説明する。
① クラス図
・クラスの内部構成や複数のクラス間の関連を記述した図
・ モデルの静的な構造を表わす図
※クラス属性 (“クラス変数”のこと)
クラスと1対1に対応して存在する属性 (通常の属性はオブジェクトと1対1 である。つまり、記述されている属性
はオブジェクトの数だけ存在する(オブジェクト変数のこと).)
−→ 同じクラスのオブジェクトすべてが1つの変数を共有する
[クラス図上での表現方法]
[実装方法]
クラス属性に $ を付ける (例えば、 $在庫量 )
メンバ変数を static として宣言する
(例えば、 int Total_num がクラス属性ならば static int Total_num とする)
−6−
2004/11/23
クラス A
属性名
操作名( )
ロール A
1..*
関連
ロール C
0..1
クラス C
属性名
操作名( )
1
集約
1..*
多重度
汎化
ロール名
クラス D
クラス B
多重度:あるクラスの1つのオブジェクトが、もう一方のクラスのいくつかのオブジェクトと関係す
るかを表わす数(最小∼最大の数を表示。* はいくつでも可)
ロール:あるクラスが他のクラスと関連する目的、立場または能力
ロール名の記述は必須ではなく、モデルに意味を追加する場合にのみ使用する
② シーケンス図
・ オブジェクト(あるいはクラス)の間の相互作用を時系列に沿って並べて表現したもの
・ 一連の処理を実現するのに必要なオブジェクトの集合とやり取りを明確に表現できる
オブジェクト A:
クラス A
オブジェクト B:
クラス B
メッセージ名
制御 の
焦点
メッセージ
ライフライン
メッセージ:オブジェクト間(クラス間)でやり取りする情報
オブジェクトの相互作用は、クライアントオブジェクト表わすライフラインから、サプラ
イアオブジェクトを表わすライフラインへ向かう水平線で表わす
制御の焦点:あるオブジェクトがフローの中で制御対象となっている相対的な時間を表わす
ライフライン:オブジェクトが生存する期間
クラス図とシーケンス図の例
Polygon
座標点の数
頂点
頂点の x 座標の取得( )
頂点の y 座標の取得( )
頂点の x 座標の表示( )
頂点の y 座標の表示( )
頂点の移動( )
頂点の座標点の出力( )
Triangle
三角形の頂点を
設定する( )
Suare
四角形の頂点を
設定する( )
1
1..*
Point
クラス図
x 座標
y 座標
点の取得( )
点の表示( )
点の移動( )
−7−
Test_OOP3
点
三角形
2004/11/23
Test_OOP3
Triangle
三角形の作成と初期値設定
Polygon
初期値設定
Point
頂点の作成と初期値設定
頂点の座標の設定
座標の出力
座標の出力
座標の取得
座標の渡し
移動の命令と移動量の設定
座標の出力
移動の命令と移動量の設定
座標の出力
座標の表示(出力)
頂点の移動(座標の変換)
座標の取得
座標の渡し
座標の表示(出力)
シーケンス図
−8−
2004/11/23
// Test_OOP3.java 多角形の処理
//--- 点
class Point{
double x;
double y;
// コンストラクタ
Point( ){ x=0; y=0; }
Point(double xx, double yy){
x=xx; y=yy;
}
//--- 四角形
class Suare extends Polygon{
Suare( ){ //--- デフォルトコンストラクタでは座標は
//
(0,0)-(1,0)-(1,1)-(0,1)
super(4);
putX(0,0); putY(0,0);
putX(1,1); putY(1,0);
putX(2,1); putY(2,1);
putX(3,0); putY(3,1);
}
Suare(double x1, double y1, double x2, double y2,
double x3, double y3, double x4, double y4){
super(4);
super.putX(0,x1); super.putY(0,y1);
super.putX(1,x2); super.putY(1,y2);
super.putX(2,x3); super.putY(2,y3);
super.putX(3,x4); super.putY(3,y4);
}
// 移動用メソッド
void move(double dx, double dy){
x+= dx; y+= dy;
}
// 座標操作メソッド
double getX( ) { return(x); }
double getY( ) { return(y); }
void putX(double xx) { x=xx; }
void putY(double yy) { y=yy; }
}
//--- 多角形
class Polygon{
int numberOfPoint;
Point point[ ];
// コンストラクタ
Polygon( ){
numberOfPoint= 1;
point= new Point[numberOfPoint];
point[0]= new Point();
}
Polygon(int n){
numberOfPoint= n;
point= new Point[numberOfPoint];
for(int i=0; i<numberOfPoint; i++){
point[i]= new Point( );
}
}
// 座標操作メソッド
double getX(int j){ return(point[j].getX( )); }
double getY(int j){ return(point[j].getY( )); }
void putX(int j, double xx) { point[j].putX(xx); }
void putY(int j, double yy) { point[j].putY(yy); }
// 移動用メソッド
void move(double dx, double dy){
for(int i=0; i<numberOfPoint; i++)
point[i].move(dx, dy);
}
// 座標点表示
void output( ){
for(int i=0; i<numberOfPoint; i++){
System.out.println("Point[" + i + "]"+
" (" + getX(i) + ", " + getY(i)+ ")");
}
}
}
}
//--- 三角形
class Triangle extends Polygon{
Triangle( ){
//--- デフォルトコンストラクタでは座標は(0,0)-(0,1)-(1,0)
super(3);
putX(0,0); putY(0,0);
putX(1,0); putY(1,1);
putX(2,1); putY(2,0);
}
Triangle(double x1, double y1, double x2, double y2,
double x3, double y3){
super(3);
super.putX(0,x1); super.putY(0,y1);
super.putX(1,x2); super.putY(1,y2);
super.putX(1,x3); super.putY(1,y3);
}
}
//-------------------------------------------class Test_OOP3{
public static void main(String args[ ]) {
//三角形の設定と移動
Triangle b= new Triangle(0.0, 0.0, 5.0, 0.0, 0.0, 5.0);
System.out.println("移動前");
b.output( );
b.move(3,-2);
// 移動
System.out.println("移動後");
b.output( );
}
}
−9−
E:¥java Test_OOP3
移動前
Point[0] (0.0, 0.0)
Point[1] (0.0, 5.0)
Point[2] (0.0, 0.0)
移動後
Point[0] (3.0, -2.0)
Point[1] (3.0, 3.0)
Point[2] (3.0, -2.0)
実行結果