人工言語入門 A 2010
Processingでオブジェクト指向プログラミング (1)
今日の内容
- オブジェクト指向でProcessingのプログラムを作る
- そもそもオブジェクト指向とは?
- 簡単なプログラムを、オブジェクト指向で書いてみる
- クラスの定義
- クラスの呼びだし
オブジェクト指向プログラミング (= OOP) について
OOP理解のポイント
- OOP = 難しい?
- OOPの難しげな用語たち
- オブジェクト
- メソッド
- メッセージ
- 継承
- 抽象化
- カプセル化
- ポリモーフィズム (多態性)
- クラス
- インスタンス化
- 言葉だけだとかなり難しそう…
- 本質を理解すると、実はやっていることは単純
プログラミング・パラダイムの変遷
- OOP以前:その1
- 非構造化ログラミング
- 全てのコードが一つの連続したブロックに含まれている
- アセンブリ言語・COBOL・BASICなど
- goto文による制御
- デバッグが難しい
- 「スパゲティプログラム」
- OOP以前:その2
- 手続型プログラミング
- 手続を呼び出す
- サブルーチン、関数
- C言語・FORTRAN・Pascal など
- 3つの基本制御パターン
- 逐次処理
- 分岐
- 繰り返し
機能中心のソフトウェア開発の問題点
- 機能、手続きを中心に構成されたプログラムの問題点
- プログラムの規模が大きくなるにつれて全体像の把握が難しい
- 機能の追加・拡張・変更が難しい
- コードの再利用が難しい – 規模が大きくなるにつれ、プログラミングにかかるコストが膨大に
- これらの欠点を改良するため、新たなパラダイムが考案される
- オブジェクト指向プログラミング (OOP)
- Simula, Smalltalk, C++, Objective-C, Java, Python, Ruby, JavaScript, C# …
- 「もの ( = オブジェクト)」の集まりとしてプログラムを構成する
オブジェクト指向プログラミングの概念
- オブジェクト指向プログラムのポイント:その1
- 「もの (= オブジェクト)」という単位でプログラムを構成する
- オブジェクトは、プロパティー(性質)とメソッド(動作・ふるまい)から構成
- 例:「りんご」をオブジェクトとして考える
- オブジェクト指向プログラムのポイント:その2
- オブジェクト同士がメッセージを送りあう
- オブジェクト指向プログラムのポイント:その3
- オブジェクトはメッセージを受け取り、それに応じた処理を行う
- メッセージの処理方法は、オブジェクト自身が知っていて、その処理はオブジェクトによって異なる (ポリモーフィズム、多態性)
- オブジェクト指向プログラムのポイント:その4
- 必要のない情報は隠す (カプセル化)
- プログラムの実装全てを知る必要はない
- 必要なインターフェイス(接点)だけ見せて、あとは隠す
- オブジェクト指向プログラムのポイント:その5
- オブジェクトから新たなオブジェクトを派生させることができる (継承)
クラス
- クラスとは:オブジェクトの「型紙」
- クラスをインスタンス化 (実体化) することでインスタンス(オブジェクト)となる
Processingでオブジェクト指向プログラミング
円を描く:いままでの方法
- まずはいままでのやり方で円を描いてみる
int x = 150; int y = 200; int diameter = 100; void setup() { size(400, 400); smooth(); noStroke(); } void draw() { background(0); ellipse(x, y, diameter, diameter); }
円を描く:クラスを宣言、属性を定義
- 円を生成するクラスを宣言する
- クラス名:Spot
- クラスのプロパティー
- float x → 円のx座標
- float y → 円のy座標
- float diameter → 円の直径
- UML(統一モデリング言語)のクラス図で上の情報を記述してみる
- クラス図:クラス、属性、クラス間の関係からシステムの構造を記述する静的な構造図
- クラスの属性の手前の記号の意味
- “+”:public クラスの外部から参照可能
- “-“:private クラスの外部からは隠蔽される(カプセル化)
Spot sp; // オブジェクトを宣言 void setup() { size(400, 400); smooth(); noStroke(); sp = new Spot(); //オブジェクトの生成 sp.x = 150; // Xの値に150を設定 sp.y = 200; // Yの値に200を設定 sp.diameter = 100; // 直径の値を100に設定 } void draw() { background(0); ellipse(sp.x, sp.y, sp.diameter, sp.diameter); } class Spot { float x, y; // X座標とY座標 float diameter; // 円の直径 }
円を描く:メソッドを定義
- Spotクラスの「動作 (= メソッド)」を定義する
- メソッドはクラス内で関数として表現される
- 必要となるメソッド
- 円を描く
- メソッド名 – void display();
Spot sp; //オブジェクトを宣言 void setup() { size(400, 400); smooth(); noStroke(); sp = new Spot(); // オブジェクトを生成 sp.x = 150; sp.y = 200; sp.diameter = 100; } void draw() { background(0); sp.display(); } class Spot { float x, y, diameter; void display() { ellipse(x, y, diameter, diameter); } }
円を描く:コンストラクタを定義
- コンストラクタ (構築子、Constructor) とは
- オブジェクトをインスタンス化する際に呼び出されて、内容の初期化などを行う関数
- クラス名と同一の名前を持つメソッドとして定義される
- 戻り値は持たない
- コンストラクタに渡す引数により初期化のバリエーションが定義される
- 例:Spotクラスのコンストラクタ
- Spot( 引数1, 引数2, 引数3 …) { }
- Spotクラスの引数に以下の2つのパラメータを渡せるようにする
- ofPoint pos;
- float diameter;
- コンストラクタをクラス図に追加
Spot sp; // オブジェクトの宣言 void setup() { size(400, 400); smooth(); noStroke(); sp = new Spot(150, 200, 100); // オブジェクトを生成 } void draw() { background(0); sp.display(); } class Spot { float x, y, diameter; Spot(float xpos, float ypos, float dia) { x = xpos; // xに150を設定 y = ypos; // yに200を設定 diameter = dia; // 直径に100を設定 } void display() { ellipse(x, y, diameter, diameter); } }
円を描く:動きを追加する
- 円をアニメーションさせてみる
- メソッドを1つと、プロパティーを1つ追加
- move() – 円の座標を更新する
- クラスSpotのプロパティーに円のスピードを追加 – float speed
- コンストラクタの引数に円のスピードを追加 – float sp
Spot sp; // オブジェクトを宣言 void setup() { size(400, 400); smooth(); noStroke(); sp = new Spot(150, 200, 100, 3); // オブジェクトを生成 } void draw() { fill(0, 15); rect(0, 0, width, height); fill(255); sp.move(); sp.display(); } class Spot { float x, y; float diameter; float speed; // 円の動きのスピード int direction = 1; // 動きの向き (1 降下, -1 上昇) // コンストラクター Spot(float xpos, float ypos, float dia, float sp) { x = xpos; y = ypos; diameter = dia; speed = sp; } void move() { y += (speed * direction); if ((y > (height - diameter / 2)) || (y < diameter / 2)) { direction *= -1; } } void display() { ellipse(x, y, diameter, diameter); } }
円を描く:複数の物体を動かす 1 – 複数のインスタンスの生成
- オブジェクトは、変数と同様に名前を変えて宣言することで複数宣言することが可能
- インスタンス化の際の引数を変化させることで、様々なバリエーションのSpotオブジェクトを同時に表示することができる
- Spotクラスから3つのオブジェクトを生成
- sp1
- sp2
- sp3
Spot sp1, sp2, sp3; //3つのオブジェクトを宣言 void setup() { size(400, 400); smooth(); noStroke(); sp1 = new Spot(100, 200, 80, 2); //sp1を生成 sp2 = new Spot(200, 200, 20, 5); //sp2を生成 sp3 = new Spot(300, 50, 60, 3); //sp3を生成 } void draw() { fill(0, 15); rect(0, 0, width, height); fill(255); sp1.move(); sp2.move(); sp3.move(); sp1.display(); sp2.display(); sp3.display(); } class Spot { float x, y; float diameter; float speed; int direction = 1; Spot(float xpos, float ypos, float dia, float sp) { x = xpos; y = ypos; diameter = dia; speed = sp; } void move() { y += (speed * direction); if ((y > (height - diameter / 2)) || (y < diameter / 2)) { direction *= -1; } } void display() { ellipse(x, y, diameter, diameter); } }
円を描く:複数の物体を動かす 2 – インスタンスの配列を生成
- インスタンスの命名では、大量のインスタンスを生成することは難しい
- 例:100コの円を同時に生成
- インスタンスを配列で管理すると、とても便利
- 配列を宣言
- 配列を生成
- それぞれのインスタンスを配列に格納
int numSpots = 20; Spot[] spots = new Spot[numSpots]; void setup() { size(400, 400); smooth(); noStroke(); for (int i = 0; i < spots.length; i++) { float x = 10 + i * 20; float rate = 2.0 + i * 0.1; spots[i] = new Spot(x, 50, 16, rate); } } void draw() { fill(0, 12); rect(0, 0, width, height); fill(255); for (int i = 0; i < spots.length; i++) { spots[i].move(); // Move each object spots[i].display(); // Display each object } } class Spot { float x, y; // X-coordinate, y-coordinate float diameter; // Diameter of the circle float speed; // Distance moved each frame int direction = 1; // Direction of motion (1 is down, -1 is up) // Constructor Spot(float xpos, float ypos, float dia, float sp) { x = xpos; y = ypos; diameter = dia; speed = sp; } void move() { y += (speed * direction); if ((y > (height - diameter / 2)) || (y < diameter / 2)) { direction *= -1; } } void display() { ellipse(x, y, diameter, diameter); } }
サンプルファイルのダウンロード
今日の授業でとりあげた、全てのプログラムは下記からダウンロードできます。
- サンプルファイルのダウンロード:proga100602_example.zip