【初心者向け】変数ではなくプロパティを公開する

ども、ゴコーです。

変数の記事の続きで、今回はプロパティについての記事です。

目次

  • 変数ではなく関数を公開する
  • プロパティを使うとどうなるか
  • 使用例
スポンサーリンク

変数ではなく関数を公開する

前回 変数は public にしない方がいい という記事を書きました。

変数を public にして他のクラスに公開すると自由に中身を書き換えられてしまいます。さらに、不正な値の書き込みへの対処も面倒でした。

そこでまずは、変数を直接公開するのではなく読み取り・書き込み用の関数をクラスに用意しましょう。

このクラスには以下のようにアクセスできます。

これで外部から score には直接アクセスできないようになりました。

不正な値もこの場合は

この部分を編集することで対処可能です…が、もっと良い書き方もあります。

それがプロパティです。

プロパティを使うとどうなるか

  • 書き方が変わる
  • 見通しがよくなる
  • 読み取り・書き込みのアクセシビリティを個別設定できる
  • 読み取りしかさせない、ということもできる
  • 読み取り・書き込みの瞬間に関数のようなことができる

書き方が変わる

当たり前ですが、書き方が変わります。先ほどのコードをプロパティを使って書き換えてみます。

get は読み取りをされた時、 set が書き込みをされた時に呼び出されます。
また、 set の value には書き込まれた値が入ります。上記の例で言えば value の値は classA.Score = 5 の「5」になります。

get, set の呼び出しは以下のように起こります。

+= の部分は classA.Score = classA.Score + 3 と同じなので get による読み取り、 set による書き込みが同時に行われます。

見通しが良くなる

普通に関数を呼んだ場合とプロパティを使用した場合には印象が変わることがあります。

先ほどのように定数を代入するのではなく、 GetPoint という関数を経由して代入することになったとします。その状態で関数を使用する場合とプロパティを使用する場合を並べてみます。

前半は かっこ が多く少し見にくいです。そして、後半の方が変更していることが瞬時に分かります。というように普通に関数を呼ぶのよりプロパティを使った方が見通しが良くなることが分かります。

少々脱線します。先ほどの例では Score = 5 というように数字を直接代入していますが、この方法は避けた方が良いです。複数人でプログラムを触る場合に、 5 という数字の意図はコメントでも書いていなければまず伝わりませんし、同じ数字を複数の箇所で使っている場合変更があればそれらすべてを手動で変更することになるからです。

ゲーム中に変更することがないと分かっているなら const を使用し、そうでないならこの項での例のように関数やプロパティを使いましょう。

読み取り・書き込みのアクセシビリティを個別設定できる

public, private などのアクセシビリティですが、プロパティの場合、読み取り・書き込みのアクセシビリティを個別に設定できます。

この例では public int Score というように Score プロパティ自体には public が設定されています。

そのため、このままでは get, set ともにどのクラスからも使用できますが、以下のようにすると書き込み(set)だけはクラス内部からしかできないようにできます。

ただし、プロパティ自体のアクセシビリティを越えるアクセシビリティは設定できません。つまり、 以下のようなことはできないということです。

読み取りしかさせない、ということもできる

書き込みを想定していない、起こってはいけない場合、 set を消して以下のように記述することができます。

読み取り・書き込みの瞬間に関数のようなことができる

これまでの例ではスコアの取得や書き込みなど、ただの変数と大差ない使い方しかしていませんが、書き込みの瞬間、関数同様に様々な処理を挟めるのもプロパティの特徴です。

使用例

最後に普段よく使っているプロパティの活用方法を紹介して終わりたいと思います。

サンプルは1つですが、意図が違うので分けて紹介します。

  • 書き込みを許さず、不正な値を入れなくする
  • 実行順序によるバグを回避する

書き込みを許さず、不正な値を入れなくする

過去に Unity5のコンポーネントキャッシュと僕の勘違い という記事を書きました。

1年以上前の記事ですが、ここに書いた通りぼくは Awake() Start() でコンポーネントキャッシュをするのはあまりよくないと思う派です。

今回はその記事同様、 Rigidbody のキャッシュを例に使います。

このようにコンポーネントキャッシュを行うコードがあるとして、プロパティに書き換えると以下のようになります。

プロパティの意味は 読み取り時に _cRigidbody の中身がなければ GetComponent() で中身を入れる、というものです。このように、 set がなくても中身を入れることも可能です。

Awake() などで変数に参照を持たせる場合、後からいくらでも書き換えることができてしまいます。

一方プロパティを使えば set を消して書き込みを許さない、ということができるわけです。_cRigidbody をクラス内から直接変更された場合はどうしようもありませんが、それでもクラス内から書き換えられているのは間違いないのでバグ発生時も速やかに対処できるはずです。

ちなみに、こういった初期化をプロパティで後から行うことを「遅延初期化」と呼ぶらしいです。

実行順序によるバグを回避する

Unity で各スクリプトの実行順序を完全に制御するのは容易ではありません。できなくはありませんが、推奨されていません。

そうなると厳しいのが初期化できていないものにアクセスした場合のバグです。

Awake() でオブジェクトAが初期化されている前提で、オブジェクトB が同じく Awake() でオブジェクトA を操作した場合、オブジェクトA の実行が先であれば普通に実行できますが、オブジェクトB の実行が先であればバグが起こる可能性があります。

しかしプロパティを使えば遅延初期化により、初期化はプロパティが 読み取られた時に 実行されるので中身がない危険性を回避できます。

さて、いかがでしたか?

プロパティと関数、実はあまり違いはありませんが、変数っぽく見通しよく使えるのが最大の利点かなとぼくは思っています。アクセシビリティの設定や不正な値の処理などは最初に書いていたとおり普通の関数でもできますしね。

遅延初期化は便利なので是非使ってみてください。

では、また。

参考:

フィールド (メンバ変数) とプロパティはここが違う
プロパティ

Comments

comments

スポンサーリンク
336*280px

コメント

  1. @rodostw より:

    RT @backlight1144: 新しい記事です: 【初心者向け】変数ではなくプロパティを公開する https://t.co/tDSlrTpiTB by Unity道しるべ

  2. @waseda_fablab より:

    RT @backlight1144: 【初心者向け】変数ではなくプロパティを公開する https://t.co/MmdwEiy11x

  3. @tomo000 より:

    【初心者向け】変数ではなくプロパティを公開する https://t.co/fcDw9rUFlj
    参考になる