[Work/Class/Java with Processing/3_ProcessingClass]

アート系学生のためのJAVA with Processing - その3-2 Processingのクラスの継承

導入

前項の「クラス」を引き継ぐ「継承」という手法を使い,自分で定義したクラスを拡張し,複数存在させる.

継承(拡張)の概念

Ballクラスは前項と同じであるが,もう一つExtendedBallというクラスを指定している.クラスを定義する時にextends(拡張する)というキーワードの後にBallクラスの名前を指定している.

継承したExtendedBallでは,Ballクラスのメンバ変数,メンバ関数が「宣言しなくても」使えるようになる.さらにメンバ変数やメンバを加えることができる.

継承元であるBallクラスのことを「親クラス」もしくは「スーパークラス」と呼び,継承先のExtendedBallクラスのことを「子クラス」もしくは「サブクラス」と呼ぶ.

コンストラクタの取り扱い

子クラスのコンストラクタの一番最初では必ずsuper();を書く.これは「スーパークラスのコンストラクタ」という意味である.

もし子クラスの中でコンストラクタを宣言しない場合,自動的に親クラスのコンストラクタが実行される.

メンバ関数のオーバーライド(Override)

親クラスに含まれるメンバ変数/メンバ関数は,子クラス内では宣言せずにそのまま使うことができるが,関数そのものを拡張したい場合が殆どである.

コード例ではBallクラスを継承したExtendedBallクラスでは,色情報を保持する変数rColor, gColor, bColorと色の増減情報rDirection, gDirection, bDrectionが含まれている.ExtendedBallクラスのupdatePosition()メンバ関数内では,今までやってきたようにこれらの情報の増減も同時に行いたい.そこでオーバーライド「関数の上書き」を行う.関数定義をもう一度書けば良い.

オーバーライドを行う場合,その関数を定義し直す頭に@Overrideキーワードをつける必要がある.

(「オーバーロード」という概念もあるが,オーバーライドとオーバーロードは別のものなので注意すること.)

コード

//ExtendsClass_Ball.pde

Ball ballArray[] = new Ball[10];
ExtendedBall extendedBallArray[] = new ExtendedBall[10];

void setup(){
  size(640, 480);
  colorMode(RGB, 255);
  background(255, 255, 255);
  frameRate(10);
  
  for(int i=0; i<10; i++){
    ballArray[i] = new Ball();
    extendedBallArray[i] = new ExtendedBall();
  }
}


void draw(){
  drawRefreshRect(255, 255, 255, 60); 
  for(int i=0; i<10; i++){
    ballArray[i].drawBall();
    extendedBallArray[i].drawBall();
  }
  
  for(int i=0; i<10; i++){
    ballArray[i].updatePosition();
    extendedBallArray[i].updatePosition();
  }
}

void drawRefreshRect(int r, int g, int b, int alpha){
  noStroke();
  fill(r, g, b, alpha);
  rect(0, 0, width, height);
}
//Ball.pde 前項と全く同じものである.
class Ball{
  int x;
  int y;
  int ballWidth = 20;
  int ballHeight = 20;
  int xDirection;
  int xSpeed;

  Ball(){
    x = (int)random(width);
    y = (int)random(height);
    
    if(random(2) < 1){
      xDirection = 1;
    }
    else{
      xDirection = -1;
    }
    
    xSpeed = (int)random(5) + 1;
  }

  void updatePosition(){
    x += xSpeed * xDirection;
    if(x > width){
      xDirection = -1;
    }
    else if(x < 0){
      xDirection = 1;
    }
  }
  
  void drawBall(){
    fill(30, 30, 30);
    ellipse(x, y, ballWidth, ballHeight);
  }
}
//ExtendedBall.pde
//Ballクラスを継承(し拡張)したもの.

class ExtendedBall extends Ball{
  //Extends: Generate Child Class from Parent Class
  //extendsキーワードで,既にある(同じプロジェクトの中に入っている)クラスを「継承」

  //継承元のクラス(親クラス)にはない,
  //継承先(このクラスのこと,子クラス)のみの変数を追加する
  int rColor;
  int gColor;
  int bColor;
  int rDirection;
  int gDirection;
  int bDirection;
   
  ExtendedBall(){
    //Execute Parent Class Constructor
    //親クラスのコンストラクタを実行するsuper();
    super();
    
    //その後に子クラスのコンストラクタ処理を記述していく
    rColor = (int)random(155) + 100;
    gColor = (int)random(155) + 100;
    bColor = (int)random(155) + 100;
    if((int)random(100) > 50){
      rDirection = 5;
      gDirection = 5;
      bDirection = 5;
    }
    else{
      rDirection = -5;
      gDirection = -5;
      bDirection = -5;
    }
  }

  @Override
  void updatePosition(){
    //@Override Keyword: 
    //Writing New Definition of Function of Parent Class
    
    //@Overrideキーワード
    //親クラスに定義されている関数の定義を上書きする(同名の関数を作る)時に使うキーワード
    //なくても動作はするが一応ちゃんと書いておくこと.

    //Overrideした時点で親クラスの同名関数は,継承したこのクラスでは空になっているので,
    //定義していく

    //Overrideしなければ,親クラスの関数がそのまま使われる
    //必要な関数のみ上書き拡張すれば良い
    x += xSpeed * xDirection;
    if(x > width){
      xDirection = -1;
    }
    else if(x < 0){
      xDirection = 1;
    }
    
    //Update RGB
    rColor += rDirection;
    gColor += gDirection;
    bColor += bDirection;

    //Update rDirection
    if(rColor > 255){
      rDirection = -5;
    }
    else if(rColor < 100){
      rDirection = 5;
    }
    
    //Update gDirection
    if(gColor > 255){
      gDirection = -5;
    }
    else if(gColor < 100){
      gDirection = 5;
    }
    
    //Update bDirection
    if(bColor > 255){
      bDirection = -5;
    }
    else if(bColor < 100){
      bDirection = 5;
    }
    
  }
  
  @Override
  void drawBall(){
    //同じくOverrideする
    fill(rColor, gColor, bColor);
    ellipse(x, y, ballWidth, ballHeight);
  }
}