(メインページへ)
4.2 アクセス制限

4.2 アクセス制限

クラスメンバーとインスタンスメンバー

クラスのプロパティとメソッドをメンバーと呼びます。クラスのメンバーにはクラスメンバーとインスタンスメンバーがあります。クラスメンバーはstaticキーワードを使って作成することから静的メンバー(静的メソッドと静的プロパティ)とも呼びます。
クラスから作ったインスタンスごとにインスタンスメンバーが作られるのに対し、クラスメンバーは1回しか作られずクラス自身に割り当てられます。そこでクラスのすべてのインスタンスで共通して利用するプロパティやメソッドはクラスメンバーとして作ります。たとえば、インスタンスが何個作られているかというカウンタや共通の割引率などはクラスメンバーにするほうが合理的です。
次のTeamクラスではインスタンスの通し番号をクラスプロパティのseqNo変数でカウントアップし、同時に各インスタンスの番号をインスタンスプロパティのmyNo変数に登録していきます。

sample→ex04-02/class_memberフォルダ

クラス定義ファイル:Team.as
class Team {
//クラスメンバー
static var seqNo:Number = 0;
//インスタンスメンバー
var myNo:Number;
var myName:String;
//コンストラクタ
function Team(memname:String) {
myNo = ++seqNo;
myName = memname;
}
//自分の情報
function who():String {
var info = myNo + "-" + myName;
return info;
}
}

ではTeamクラスをテストしてみましょう。Flashムービーを作り、フレーム1のフレームアクションに次のスクリプトを書きます。名前を引数に指定してTeamクラスのインスタンスを作ります。そしてそれぞれのインスタンスのmyNoとmyNameの値をwho()関数で調べると、myNoには各インスタンスの通し番号が入っていることがわかります。


フレームアクション:teamtest.fla
var yo:Team = new Team("大重美幸");
var ty:Team = new Team("山本太郎");
trace(yo.who()); //出力→ 1-大重美幸
trace(ty.who()); //出力→ 2-山本太郎

個別リンク

クラスメンバーにアクセスする

クラスメンバーはビルトインクラスのMathクラスなどの使い勝手と同じように、インスタンスを作らなくともアクセスできる手軽さがあります。そこで次のようなKansanクラスを作れば、摂氏を華氏に換算するといった関数を手軽に利用できるようになります。


sample→ex04-02/class_memberフォルダ

クラス定義ファイル:Kansan.as
class Kansanki {
//摂氏を華氏に換算して返す
static function kashi(c:Number):Number {
var f = 1.8 * c + 32;
return f;
}
//華氏を摂氏に換算して返す
static function sessi(f:Number):Number {
var c = (f - 32) / 1.8;
return c;
}
//コンストラクタ
function Kansan() {
}
}


ムービーのフレームアクションに次のように書いてムービープレビューを行うと、kashi()関数の値が書き出されます。このようにクラスメンバーにはインスタンスを介さずに直接アクセスします。、


フレームアクション:classMemTest1.fla
var f = Kansan.kashi(20);
trace(f + "F"); //出力→ 68F
var c = Kansan.sessi(50);
trace(c + "C"); //出力→ 10C

note:
ビルトインクラスのMathクラスなどはインスタンスを作らなくとも利用できますが、その理由はPIやrandom()などがクラスメンバーだからです。

個別リンク

メンバーアクセスの制限(publicとprivate)

publicとprivateは、ほかのクラスやインスタンスからのプロパティ参照やメソッド実行にアクセスに制限を付けるためのキーワードです。デフォルトではメンバーアクセスに制限がなく自由に利用できますが、これは次の例に示すpublicキーワードが省略されている状態と言えます。

sample→ex04-02/publicフォルダ

クラス定義ファイル:MyClass01.as
class MyClass01 {
public var counter:Number = 0;
//コンストラクタ
public function MyClass01() {
}
//メソッド
public function countUp() {
counter++;
return ("counterの値は" + counter);
}
}


デフォルトでは、クラス定義されているプロパティを調べたりメソッドを実行したりすることをほかのクラスやインスタンスから自由に行えますが、これにアクセス制限を付けることができます。
次のBallPubクラスは動き回るボールを作ります。ボールは320×240の領域内で動き回り、壁に当たると跳ね返ります。

sample→ex04-02/privateフォルダ

クラス定義ファイル:BallPub.as
class BallPub {
//パブリック変数
public var mc;
public var dx;
public var dy;
//コンストラクタ
function BallPub(target:MovieClip, x:Number, y:Number) {
this.mc = target;
this.dx = x;
this.dy = y;
}
//ボールの動き
function f1() {
//壁で跳ね返る
if ((mc._x < 0) || (mc._x > 320)) {
dx *= -1;
}
if ((mc._y < 0) || (mc._y > 240)) {
dy *= -1;
}
//ボールの移動
mc._x += dx;
mc._y += dy;
}
}

BallPubクラスのmc、dx、dyはパブリック変数なので、ほかのクラスから参照して値を変更することができます。privateEx1.flaではmyBtnボタンをクリックするたびにdxとdyの値に-1を掛けて移動方向を反転してます。


フレームアクション:privateEx1.fla
var obj1:BallPub = new BallPub(ball_a, 5, 4);
//publicなメソッドにアクセスする
this.onEnterFrame = function () {
obj1.f1();
};
//publicなプロパティにアクセスする
//ボタンクリックで移動方向を反転する
myBtn.onPress = function(){
obj1.dx *= -1;
obj1.dy *= -1;
}

図4-2-1 ボタンをクリックするとボールの動く向きが反転します。


次のBallPvクラスはBallPubクラスと同じスクリプトですが、mc、dx、dyがプライベート変数になってます。このため、BallPvクラスのように外から移動速度を変更することができません。

クラス定義ファイル:BallPv.as
class BallPv {
//プライベート変数
private var mc;
private var dx;
private var dy;
//コンストラクタ
function BallPv(target:MovieClip, x:Number, y:Number) {
this.mc = target;
this.dx = x;
this.dy = y;
}
//ボールの動き
function f1() {
//壁で跳ね返る
if ((mc._x < 0) || (mc._x > 320)) {
dx *= -1;
}
if ((mc._y < 0) || (mc._y > 240)) {
dy *= -1;
}
//ボールの移動
mc._x += dx;
mc._y += dy;
}
}


次のようにインスタンスからプライベート変数のdx、dyにアクセスするとその部分がコンパイルエラーになります。

var obj1:BallPv = new BallPv(ball_a, 5, 4);
//publicなメソッドにアクセスする
this.onEnterFrame = function () {
obj1.f1();
};
//以下はプライベート変数にアクセスするのでコンパイルエラーになる
myBtn.onPress = function(){
obj1.dx *= -1;
obj1.dy *= -1;
}

note:
privateの指定はスクリプトの実行時に変数やメソッドへのアクセスを制限するというものではなく、厳密なデータ型などと同様にコンパイル時にチェックされる制限事項です。

*訂正 (2006.06.19 )
初版 p.128、p.130
初版では論理和の演算子orを使っていました。orは使用を推奨されていない演算子なので、orの代わりに||を使ってください。申し訳ないです。(う〜ん、ちょうどこれを書いている頃にLingoを使っていたのかも・・・・)

訂正前:
//壁で跳ね返る
if ((mc._x < 0) or (mc._x > 320)) {
dx *= -1;
}
if ((mc._y < 0) or (mc._y > 240)) {
dy *= -1;
}

訂正後:
//壁で跳ね返る
if ((mc._x < 0) || (mc._x > 320)) {
dx *= -1;
}
if ((mc._y < 0) || (mc._y > 240)) {
dy *= -1;
}

個別リンク

暗黙的なgetterメソッドとsetterメソッド

オブジェクト指向プログラミングの作法では、ほかのクラスのプロパティの値を直接書き換えたり読み出すこと良しとしない考え方があります。ではどうやって、ほかのクラスからプロパティにアクセスするかと言えば、プロパティの値を設定したり返したりする専用のメソッド、すなわち、getterメソッドとsetterメソッドをクラス内で定義しておき、それを介してのみアクセス可能にします。
しかしこれではクラスを利用するユーザーにとって手軽さを欠いたものになりかねません。そこでgetとsetのキーワードを使い、暗黙的なgetterメソッドとsetterメソッドを定義します。これであたかもプロパティに直接アクセスしているかのように見せることができます。
たとえば、次のGameクラスにはplayerNameとgamePointの2つのプロパティが使ってあります。GameクラスのインスタンスmyGameを作ったとき、2つのプロパティはプライベート変数であることから、myGame.playerName、myGame.gamePointのように簡単にアクセスすることができません。


sample→ex04-02/getsetフォルダ

クラス定義ファイル:Game.as
class Game {
//プライベート変数
private var playerName:String;
private var gamePoint:Number = 0;
//コンストラクタ
function Game(name:String) {
this.playerName = "Bomber_" + name;
}
//暗黙のgetterメソッド
function get player():String {
return this.playerName;
}
//暗黙のsetterメソッド
function set player(name:String):Void {
this.playerName = name;
}
//暗黙のgetterメソッド
function get point():Number {
return this.gamePoint;
}
//暗黙のsetterメソッド
function set point(v:Number):Void {
this.gamePoint = v;
}
}

しかし、get、setのキーワードを使ってplayerとpointのメソッドが定義してあることから、次のように外見上はオブジェクトのプロパティに直接アクセスしているかのように、2つのプロパティに気軽にアクセスすることができます。Gameクラスをブラックボックスと考えるならば、GameクラスのユーザーにとってはplayerとpointがGameクラスのプロパティとして見えます。

フレームアクション:getsetTest.fla
var myGame:Game = new Game("oshige");
myGame.point = 59;
trace(myGame.player); //出力→ Bomber_oshige
trace(myGame.point); //出力→ 59

note:
v2コンポーネントはget、setを利用することでユーザーにとってシンプルな使い勝手を実現してます。

個別リンク