ごみ箱機能を作る

# 隠れた必須機能、ごみ箱

人間は間違えます。
人間にデータ操作をさせるGUIアプリケーションにおいて、削除したデータを退避し、後に復元することを可能にするごみ箱機能は必須と言えるかもしれません。

そんなごみ箱を作ってみます。
言語はTypescriptです。

# ごみ箱に必要な機能は？

ごみ箱には最低限、以下の機能が必要でしょう。

・ごみ箱にデータを捨てる
・ごみ箱からデータを取り出す
・ごみ箱内の指定したデータを永久に削除する
・ごみ箱を空にする

データオブジェクトにはUUIDのような一意の文字列型のIDが割り振られているものとします。
これらを踏まえ、以下のようなごみ箱クラスを考えます。

```trash-can.ts
class TrashCan {
  trashedObjs: Array<{ obj: MyObject; trashedDate: string }> = []

  //ごみ箱に捨てる
  put(objs: Array<MyObject>): void {}

  //ごみ箱から取り出す
  salvage(ids: Array<string>): MyObject[] {}

  //永久に削除
  burn(ids: Array<string>): void {}

  //ごみ箱を空にする
  empty(): void {}
}
```

順に実装していきます。

## ごみ箱に捨てる

データの配列を受け取り、削除日時とセットにしてストアします。
`push()`だと配列の末尾に挿入されますが、ごみ箱の場合後から捨てられたものを先頭に追加していった方がGUIで表示するうえで都合がいいので、`splice(0, 0, ...)`としています。

関数名は、最初は「捨てる」を意味する`dispose`等にしようかと思いましたが、ごみ箱「に」捨てるのではなく、ごみ箱の中身「を」捨てるように見えて紛らわしいので、直接的に「入れる」をイメージさせる`put`にしてみました。

```trash-can.ts
  put(objs: Array<MyObject>): void {
    objs.forEach((e) => {
      this.trashedObjs.splice(0, 0, {
        obj: e,
        trashedDate: new Date().toJSON(),
      })
    })
  }

```

## ごみ箱から取り出す
`map`を使って日付情報も含んだ`this.trashedObjs`を`MyObject`の配列に変換したうえで、引数として受け取ったIDに一致するものが格納されたインデックスを探します。

`splice(startIndex, deleteCount)`を使うと、対象となるデータを配列から削除しつつ戻り値として受け取ることができます。

受け取ったデータを返します。

```trash-can.ts
  salvage(ids: Array<string>): MyObject[] {
    const salvaged = Array<MyObject>()

    ids.forEach((id) => {
      const targetIndex = this.trashedObjs
        .map((e) => e.obj)
        .findIndex((e) => e.id === id)
      const targetTrash = this.trashedObjs.splice(targetIndex, 1)
      salvaged.push(targetTrash[0].obj)
    })

    return salvaged
  }
```

## 永久に削除
永久に削除します。燃やします。`burn`です。
削除したデータを返さないだけで先ほどとほぼ同じです。

```trash-can.ts
  burn(ids: Array<string>): void {
    ids.forEach((id) => {
      const targetIndex = this.trashedObjs
        .map((e) => e.obj)
        .findIndex((e) => e.id === id)
      this.trashedObjs.splice(targetIndex, 1)
    })
  }
```

## 空にする
全部消します。簡単ですね！

```trash-can.ts
  empty(): void {
    this.trashedObjs.splice(0)
  }
```

# 完成
というわけで、以下のようになりました。

末尾で`export default new TrashCan()`しています。
通常、ごみ箱は一つのアプリケーションに一つしかありません。
`export default new TrashCan()`とすることで、これをモジュールとして`import`すればどこでも同じごみ箱インスタンスを参照することができるようになります。

```trash-can.ts
class TrashCan {
  trashedObjs: Array<{ obj: MyObject; trashedDate: string }> = []

  //ごみ箱に捨てる
  put(objs: Array<MyObject>): void {
    objs.forEach((e) => {
      this.trashedObjs.splice(0, 0, {
        obj: e,
        trashedDate: new Date().toJSON(),
      })
    })
  }

  //ごみ箱から取り出す
  salvage(ids: Array<string>): MyObject[] {
    const salvaged = Array<MyObject>()

    ids.forEach((id) => {
      const targetIndex = this.trashedObjs
        .map((e) => e.obj)
        .findIndex((e) => e.id === id)
      const targetTrash = this.trashedObjs.splice(targetIndex, 1)
      salvaged.push(targetTrash[0].obj)
    })

    return salvaged
  }

  //永久に削除
  burn(ids: Array<string>): void {
    ids.forEach((id) => {
      const targetIndex = this.trashedObjs
        .map((e) => e.obj)
        .findIndex((e) => e.id === id)
      this.trashedObjs.splice(targetIndex, 1)
    })
  }

  //ごみ箱を空にする
  empty(): void {
    this.trashedObjs.splice(0)
  }
}

export default new TrashCan()
```