3
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

変数もお財布もprivateで管理しましょう

Last updated at Posted at 2018-04-25

この記事を書いた人

積木製作( http://tsumikiseisaku.com/ )という
VRなどのコンテンツを作っている会社でエンジニアをやってます。
もくもく会( https://kinmokukai.peatix.com/view )の主催とかもしています。

導入

VRなどの開発には現在UnityやUE4がベースとして使われており、
こうしたゲームエンジンはオブジェクト指向に対応しています。
で、そのオブジェクト指向でプログラミングをする時には、
ちょっとしたコツを知っているかどうかで効率が大きく変わる場面があります。

image.png
今回はこうしたTipsの一つ「変数もお財布もprivateで管理しましょう」を解説します。

アクセサー(アクセス指定修飾子)について

アクセサーとは

オブジェクト指向の特徴として
あちこちで「private」「protected」「public」などを見かけると思います。

クラス(型)やストラクト(構造体)を宣言するときにも使ったりしますが、
特に重要なのはその中で宣言する 「メンバ変数」のアクセサーです。

そもそも、アクセサーというのは「誰がここにアクセス(干渉)」できるのかを表すキーワードです。

C系列の言語で入門書を見ると、だいたい、以下のように説明されていると思います。
public <= おおやけのもの、制限をしないもの、誰でも触れるもの
protected <= 自分と自分を継承した相手だけが触れるもの
private <= 外から触れないもの、内側に閉じ込めたいもの

こうした説明に間違いはありませんが、
そもそも「どうしてこんなものが必要なのか」について、
ちゃんと踏み込んでいる本はほとんどありません。

しかしこれって実は
プログラムの作りやすさ、バグの直しやすさが何百倍も変わるポイント
だったりします。

publicの実例(コレでいいじゃん)

上の説明だけだと、どうみたって全部publicにすべきです。
入門書ではだいたいのメンバー変数がpublicですし、
ネットで見かけるコピペ元のソースコードもpublicがわりと使われています。
実際に手軽です。

たとえば

Monsterクラスは主人公を攻撃できるようにしよう!
Atack関数でPlayerインスタンスのHPを10減らそう!

image.png

という処理を思いついた場合、まずこんな形で実装したくなると思います。

public.cs
class Player {
   public int HP = 100;
}

class Monster {
   public void Atack (Player player){
      player.HP -= 10;
   }
}

PlayerのPublicなHPにズドーン!とダメージが入っています。
処理も数行ですし、素直で書きやすいし、読みやすい。

privateの実例(まわりくどいよね)

もしこれがprivateだったらどうなるでしょう。
同じ処理について、PlayerのHPがprivateでも動くようにしたプログラムがこちら。

private.cs
class Player {
   private int HP  100;

   //HPにダメージがはいったら呼び出します
   public void HpDamage (int damage){
      HP -= damage;
   }
}

class Monster {
   public void Atack (Player player){
      player.HoDamage(10);
   } 
}

まず、長くなってますよね。

関数もPlayerクラスに一つ増えてます。

MonsterのAtackの中にはシンプルだった計算処理から、
何をやってるかよくわからないけど、
HoDamageっていう関数の呼び出し処理が入っています。

結果として上の処理と同じ結果になるようにしていますが、
実に回りくどい。

今回はHPだけだから許せるけど、MPもSPも所持金もEXPも管理ってなったら、
この何倍の関数を書いて並べることになるか。。。
image.png
ゆめもきぼうも、ないんだよ。

privateを使うのは暇人だけ。。。?

ここまで読んでもらった印象では、いかがでしょうか。
僕もわりと長い間、
「回りくどい書き方をしたり、
 俺って難しい書き方できるんだぜー、意識高いぜーみたいな人が使うのがprivate」
みたいに思っていました(え、そこまでじゃない?)

ただ、privateが「作る人にとって邪魔な機能」なら、
どうして未だに残っているのでしょうか。

それは「作るときに回りくどくなっても、
その何倍もの利点があるから」にほかなりません。
image.png

privateの主な効能

バグはいつ、どこで、なぜ生まれたか

変数をprivateにすることで、
その中身は基本的に「外から変更できない」ことになります。

上の例だと実感は難しいですが、
PlayerのHPを変更できる存在が20種類いる状態を創造してみてください。

攻撃のAtackだけでなく、回復のHealとか、ちょっとずつ減らす毒状態のPoisonDotとか、
たくさんのクラスでplayer.HP -= 10とかplayer.HP += 4が書かれていくわけです。
image.png

こういう状態で何か問題が起きたとき、
バグを直すために必要な「誰がいつ、どうしてどんな状態にしたのか」という情報は。
残念ながらその場だとほとんど手に入れられません。
複数のクラスやファイルなどを飛び回り、関連箇所を探し回るわけです。

コードの行数が多ければ多いほど、このPlayer.HPへの計算処理もあるはずです。

複数のファイルから一つも漏らさず、
ただし何度も同じファイルを読み返す無駄もしないで、
本当に正しい処理が正しいタイミングで行われていて、
その処理に問題がないのか確認する。

想像しただけでも、このデバッグは絶対に面倒臭いです。
image.png

privateにして自分が管理していれば、
すくなくともHPは自分の外から変化されてないはずなので、
探べきファイルもクラスも一つだけで良くなります。らくちん!

どうして、なにをするの?

さらに、どこかの場所でHpHeal(回復)みたいな関数の中で、
「HP -= 20」って処理が行われていたらどうでしょうか。
これは回復するべき「HP += 20」を書き間違えたのか、
主人公が実はHealされるとダメージを受ける特殊体質で、正しい処理なのか、
「三年後の自分が読んで思い出せる」コードでしょうか。
僕は無理です。無理ならきっとここもバグの発生源です。
image.png

そこで値そのものはprivateにして、下記のようになっていたらどうでしょう。

sample.cs
class Player{
   private HP = 100;
   private bool isZonbie = true;
   public void HpDamage(int damage){,,,}
   public void HpHeal(int heal){
      // ゾンビ状態(isZonbie=true)だと-healが加わる
      HP += isZonbie ? -heal: heal;
   }
}

class Healer{
   public void Heal(Player player){
      player.HpHeal(20);
   }
}

ヒーラーが間違いなく、正しいヒールを行っていることがわかりますし、
主人公がゾンビだろうが健康だろうが、気にせずヒールできるようになっています。

こうした構造はプログラミングに慣れていれば自然に書けるようになりますが、
その「慣れ」の中で重要なのがこのprivateを使うこと。

直接アクセスができないから、関数を経由してアクセスをする。
その時につける関数の名前で「なんのための処理なのか」をちゃんと表現すれば、
プログラマーの「どうしてそう書いたのか」という意志と判断がソースコードに残るわけです。
この残された「プログラムの動きではない情報」が、バグの解決ではなにより重要になります。

変数もお財布もprivateで管理しましょう

あなたは自分のお財布を公共の場所において、
誰からでも出し入れ自由な状態になっていたら、どうでしょうか。

今月分の家賃が入っていたとしても
「万が一なんて、ほぼ発生しないから万が一でしょ?」と
のんびり構えていられるでしょうか。
image.png

プログラムの世界で考えれば
YouクラスのPocket変数がpublicというのは、こういう状態です。

privateなメンバー変数は
そのクラスの中からだけ干渉できるというルールです。

自分以外には触られないことは面倒ですが、
自分で面倒を見ている限り、
中身が予定より減っていたとしても、
それは間違いなく自分のせいだと言い切れるわけです。
image.png

だれが間違えたのかは明確なので、
あとは「いつ、なぜ、どこで」まちがえたのかを、
自分の関数の中から探すだけです。
複数のソースコードを飛び回る必要もなく、
きっと少しスクロールするだけで終わります。

小さなプログラミングは動けばとりあえずかまいません。
でも、一定より大きなプログラムを作ろうとすると、
「書く」よりも「読む」方が多くなっていきます。

今書いているコードから、
あなたは未来のあなたに何を伝えているでしょうか?

こうした「何をソースコードに残すか」という
コミュニケーション意識を持ったコーディングをすることで、
少しずつ大きなプログラムを負担なく作れる技術が身について
初心者から初級者にあがっていくことができるようになります。

どうかこの記事が少しでもお役にたちますように。
みなさんの開発の幸運を祈ります。

出展・引用

いらすとや さま
Wikipedia さま

3
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?