【Day14】君は完璧で究極のセッター！(またはゲッター！)【QAC24】


# こんな時、あなたならどうする？

まぁこれからはタイルお絵描きをしていくのですが...
レイヤーの機能は説明したかな？

`realtiles`や`tiles`の中は 2 次元配列になっているのですが、1 次元目がレイヤーで、2 次元目がタイルの配列となっています。

```typescript
const tiles = [
  ["Tile1 on Layer1", "Tile2 on Layer1"],
  ["Tile1 on Layer2", "Tile2 on Layer2"],
];
```

まぁだいぶ雑に書くとこんな感じ。

んで、お絵描きマップ（タイルエディター）の中では、レイヤーを管理するプロパティとして`layer`でも作っておくべきですよね。
じゃないと今どのレイヤーかとか分かりませんから。マウスは 3 次元空間には存在しないので。

```typescript:/src/maps/editorMap.main.ts
export class EditorMapMain extends GameMap {
  private layer: number = 0;
}
```

とこんな感じに書きましたが、レイヤーに負の数っていりますか？
いらないですよね。なんなら 0 もいらないですよね。...いや、配列のアクセスが 0 から始まるんだから 0 はいるか。

まぁどんな方法を使ってもいいでしょう。
例えば`NaturalNumber`みたいな型を作って。（今回は自然数に 0 を含めましょう。）

```typescript:NaturalNumber.ts
type NaturalNumber = number;

const isNaturalNumber = (n: number): n is NaturalNumber => n >= 0;
```

確かにいいんですが、お絵かきソフトを使った人なら、レイヤーのほかに特殊レイヤー...例えば選択レイヤーとかを見かけたことがあるかもしれません。
こんな感じで、特殊なレイヤー...後の方の記事で出てくるような当たり判定などもレイヤーとしておけば便利にマップビルドが出来ますよね。

その特殊なレイヤーに数値を付けるなら、それらは必然的にマイナスになると思います。
だから NaturalNumber ではないですね。

じゃあ、`number`だけど、ある値以下の値を入れたときにエラーを吐かせるような感じにしましょうか

```typescript:/src/maps/editorMap.main.ts
export class EditorMapMain extends GameMap {
  private _layer: number = 0;

  private setLayer(layer: number) {
    if (layer < 0) {
      // 説明がめんどくさくなるから、今回は0以上の数値のみを許可
      throw new Error("Layer must be a natural number.");
    }
    this._layer = layer;
  }

  private getLayer(): number {
    return this._layer;
  }
}
```

`setLayer`と`getLayer`というものを作ってみました。
ちょっと不格好だけど出来ましたね！

# 君は完璧で究極のセッター！(またはゲッター！)

不格好だと思われたあなたは、もっと素敵なコードが書けます。

TypeScript 含め、多くの言語の Class には、`getter`(ゲッター)と`setter`(セッター)というものがあります。
これは、ある値の取得や設定を行う際に、間に挟まってなんかいろいろ処理を行うようなものです。

TypeScript においては、`get`と`set`というキーワードを使って、それぞれのメソッドを作成することが出来ます。

```typescript:/src/maps/editorMap.main.ts
export class EditorMapMain extends GameMap {
  private _layer: number = 0;

  get layer(): number {
    return this._layer;
  }

  set layer(layer: number) {
    if (layer < 0) {
      // 今回は0以上を許可以下略
      throw new Error("Layer must be a natural number.");
    }
    this._layer = layer;
  }
}
```

先ほどと似たような感じですが、先ほどのコードよりも自然に`layer`を操作できます。

```typescript
const map = new EditorMapMain();

map.layer = 1;
console.log(map.layer); // 1

map.layer = -1; // Error: Layer must be a natural number.
```

このように、`layer`を直接操作することが出来つつも、`set`を通して値を設定するこうすることで、値の制約をかけることが出来ます。

また、`get`になんか色々つけたら、値を読み込まれたときに何か処理を挟むことも出来ます。

```typescript:/src/maps/editorMap.main.ts
export class EditorMapMain extends GameMap {
  private _layer: number = 0;

  get layer(): number {
    console.log("うわ！ 読まれた！");
    return this._layer;
  }

  set layer(layer: number) {
    if (layer < 0) {
      // 今回は0以上を許可以下略
      throw new Error("Layer must be a natural number.");
    }
    this._layer = layer;
  }
}
```

まぁ実演せずともなんとなくわかると思いますが、`get`が呼ばれるたびに`console.log`が呼ばれるようになります。

```typescript
const map = new EditorMapMain();

console.log(map.layer); // "うわ！ 読まれた！"が表示されてから、0が表示される
```

このように、`getter`と`setter`を使うことで、値の取得や設定時に何か処理を挟むことが出来ます。
例えばセッターは、値の制約をかけるためや、値が変更されたときに別の値も変更するために使うことが出来ます。
ゲッターは、そうですね...値を取得されたときに計算をした値を返すために使うことが出来るでしょう。

# 明日の希望を取り戻そうぜ

明日は、絵の具を使うときに必要なあれを説明していきます。
分からないなら絵の具を使って絵でも描いてください。素晴らしい絵を描いてくださった方のうち、抽選で 1 名様に ping を飛ばします。

それでは、また明日！

https://dic.pixiv.net/a/%E5%90%9B%E3%81%AF%E5%AE%8C%E7%92%A7%E3%81%A7%E7%A9%B6%E6%A5%B5%E3%81%AE%E3%82%B2%E3%83%83%E3%82%BF%E3%83%BC