Facadeパターンって何の役に立つの？

# 目的
Facadeパターンが何の役に立つのかを簡単に説明する（コード有り）

# Facadeパターンはどんな役に立つか？
簡単にいうと、**複数の処理のまとめ役**。
なので、依頼1つでいろんな仕事をやってくれる点で役に立つ。

# Facadeパターンの要件
- Facadeクラスはあくまでサブシステム内部に仕事を投げるだけで複雑な実装は持たない。
- Facadeクラスをサブシステム自体が利用する事はない。
- Facadeパターンはサブシステムの直接使用を妨げない。

# クラス図
## Facadeパターンのクラス図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190809/8dc7125b-3a8c-03c1-71a2-d4be2533b4cd.png)
> 引用元：[Wiki - Facadeパターン](https://ja.wikipedia.org/wiki/Facade_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3)

## 今回説明するコードのクラス図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190809/0befb2ed-c2ee-22d8-1149-da5b0bba5a27.png)
LibrarianがBookListとLendingListを持っているのは立場上の仕様であり、窓口になって利用するという実装自体に変わりはありません。

## クラス図の各役割
Facade：Librarianクラス
サブシステム：BookListクラス、LendingListクラス
クライアント：Visitorクラス

## 各クラスの関わり
- Librarian（司書）は本を探す役割を引き受けることができる。
- Visitor（利用者）はLibrarianに本を探すことを依頼できるし、自分で探すこともできる。
- BookList（貯蔵本台帳）とLendingList（貸出帳）は、LibrarianまたはVisitorから利用される。

# コード
```Librarian.java
package facade;

// 司書
public class Librarian {
    private BookList _bookList;
    private LendingList _lendingList;

    Librarian(BookList bookList, LendingList lendingList){
        _bookList = bookList;
        _lendingList = lendingList;
    }

    public String searchBook(String bookName) {
        //所蔵されているか？
        if(!_bookList.existsBook(bookName)) return "その本は所蔵していません";

        //書棚にあるか？
        if (_lendingList.isLending(bookName)) return "貸出中です";

        // 所蔵場所
        return _bookList.searchLocation(bookName);
    }
}
```

```BookList.java
package facade;

import java.util.HashMap;
import java.util.Map;

//所蔵本台帳
public class BookList {
    private Map<String, String> _record = new HashMap<String, String>();

    public void addRecord(String bookName, String locationName) {
        _record.put(bookName, locationName);
    }

    public boolean existsBook(String bookName) {
        return _record.containsKey(bookName);
    }

    public String searchLocation(String bookName) {
        return (String)_record.get(bookName);
    }
}
```

```LendingList.java
package facade;

import java.util.ArrayList;
import java.util.List;

//貸出帳
public class LendingList {
    private List<String> _record = new ArrayList<String>();

    public void lending(String bookName) {
        _record.add(bookName);
    }

    public void returned(String bookName) {
        _record.remove(bookName);
    }

    public boolean isLending(String bookName) {
        return _record.contains(bookName);
    }
}
```

```Visitor.java
package facade;

public class Visitor {
    private String _name;
    private String _targetBookName;

    Visitor(String name){
        _name = name;
    }

    public void setTargetBookName(String targetBookName) {
        _targetBookName = targetBookName;
    }

    public String targetBookName() {
        return _targetBookName;
    }

    public String name() {
        return _name;
    }
}
```

``` Main.java
package facade;

import java.io.PrintStream;

public class Main {
    public static void main(String[] args) {
        // 初期値セット
        // (所蔵本リスト)
        BookList bookList = new BookList();
        bookList.addRecord("昆虫図鑑", "棚番号1");
        bookList.addRecord("動物図鑑", "棚番号1");
        bookList.addRecord("桃太郎", "棚番号2");
        bookList.addRecord("金太郎", "棚番号2");
        bookList.addRecord("コンピュータの仕組み", "棚番号3");
        bookList.addRecord("Javaプログラミング", "棚番号3");
        // (貸出リスト)
        LendingList lendingList = new LendingList();
        lendingList.lending("昆虫図鑑");
        lendingList.lending("桃太郎");
        lendingList.lending("コンピュータの仕組み");

        PrintStream out = System.out;

        // 利用者[山田くん]：司書[中村くん]に依頼する場合
        Visitor yamada = new Visitor("山田");
        yamada.setTargetBookName("昆虫図鑑");
        // (窓口[中村くん])
        Librarian nakamura = new Librarian(bookList, lendingList);
        // (中村くんに昆虫図鑑の場所を聞く)
        out.println(yamada.name() + "の結果：");
        out.println(nakamura.searchBook(yamada.targetBookName()));
        out.println();

        // 利用者[木下くん]：自分で探す場合
        Visitor kinoshita = new Visitor("木下");
        kinoshita.setTargetBookName("動物図鑑");
        if(!bookList.existsBook(kinoshita.targetBookName())) {
            out.println("他の本にしよう");
            return;
        }
        if(lendingList.isLending(kinoshita.targetBookName())) {
            out.println("他の本にしよう");
            return;
        }
        out.println(kinoshita.name() + "の結果：");
        out.println(bookList.searchLocation(kinoshita.targetBookName()));
        out.println();
    }
}
```
山田くん、木下くんのtargetBookNameを変更して、動作を確認してみて下さい。

## Github
https://github.com/TakumiKondo/designpattern/tree/master/src/facade/librarian

# 使いどころ
複数の処理を呼び出す一連のコードを色んな箇所に書き始めたら、
Facadeパターンを使うことを検討してみてほしい。

ただし要件にある通り、複雑なロジックを含んではならないため、
あくまで、処理の束ね役に徹することが求めれます。

# 参考
Facadeパターン
https://ja.wikipedia.org/wiki/Facade_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3

コードの引用元（これを基に改造しました）
https://www.techscore.com/tech/DesignPattern/Facade.html/