Abstract Factoryパターン 例（サカつくの場合）

# 背景
デザインパターンの本を読んで、わかったつもりになっていても、いざ使おうとしたときに使えない。
いたずらにパターンを適用しようとしても逆効果になるかもしれない。
使いこなすためには、どんなときにパターンを適用すれば良いか理解したうえで、応用できないといけない。
なので、使えそうなときはどんなときか身近な例を考えて作ってみました。

# 参考資料

* [増補改訂版 Java言語で学ぶデザインパターン入門](https://www.amazon.co.jp/増補改訂版-Java言語で学ぶデザインパターン入門-結城-浩-ebook/dp/B00I8ATHGW/ref=sr_1_4?__mk_ja_JP=カタカナ&crid=2LX5EGSDGEHES&keywords=デザインパターン&qid=1670657193&sprefix=デザインぱたーn%2Caps%2C350&sr=8-4)

* [オブジェクト指向における再利用のためのデザインパターン](https://www.amazon.co.jp/オブジェクト指向における再利用のためのデザインパターン-エリック-ガンマ/dp/4797311126/ref=sr_1_1?keywords=オブジェクト指向における再利用のためのデザインパターン&qid=1670657488&sprefix=オブジェクト指向における再利用のための%2Caps%2C190&sr=8-1)

# Abstract Factory 解釈
* 直訳では「抽象的な工場」ですが、いろんな部品を組み合わせて一つの製品を作るときに有効なパターンで、部品は固定であるときが有効
* 逆にいちいち部品が変わる場合は使わない方が良い

僕の身の回りでどんなケースがあるか考えたときに、
サッカーは11人でやるもので監督が戦術を決めて、選手がプレーすることは変わらない、というのを題材にしてみようと思いました。

# クラス
![無題のマップ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1878269/5c9fe07a-c034-24a4-5d19-066e50c5db42.png)

サッカーチームファクトリーがAbstract Factoryクラス、
FW、監督クラスは抽象部品クラスです。
サンフレファクトリークラス、日本代表クラスが具体的なファクトリークラス
ピエロス・ソティリウ、堂安、スキッベ、森保が具体的な部品クラスです。

今年のサンフレッチェは、なんといっても2022年度最優秀監督賞を取ったスキッベ監督ですよね。
FWのピエロスですが、今年はルヴァン杯での決勝戦でヒーローになりましたが、来年はリーグ戦での活躍を期待してます。

※クラス図はGitMindで作成

# 実装(抽象クラス)
```cpp:Abstract.h
#pragma once

/* Abstract */
class abstract_FW{
    public:
        virtual void shoot() = 0;
        virtual ~abstract_FW(){}
};

/* Abstract */
class abstract_Manager{
    public:
        virtual void tactics() = 0;
        virtual ~abstract_Manager(){}
};

/* Abstract */
class soccerteam_Abstractfactory{
    public:
        virtual abstract_FW *CreatePlayer() = 0;
        virtual abstract_Manager *CreateManager() = 0;
        virtual ~soccerteam_Abstractfactory(){};
};


```

# 実装(具象クラス)
```cpp:Sanfrecce.h
#pragma once

/* Concrete */
class PIEROS_SOTIRIOU : public abstract_FW{
    public:
        void shoot();
        ~PIEROS_SOTIRIOU(){}
};

/* Concrete */
class Skibbe : public abstract_Manager{
    public:
        void tactics();
        ~Skibbe(){}
};

/* Concrete */
class Sanfrecce : public soccerteam_Abstractfactory{
    public:
        abstract_FW *CreatePlayer();
        abstract_Manager *CreateManager();
        ~Sanfrecce(){}
};


```

```cpp:Sanfrecce.cpp
#include <iostream>
#include "Abstract.h"
#include "Sanfrecce.h"

/* Concrete */
void PIEROS_SOTIRIOU::shoot(){
    std::cout << "PIEROS_SOTIRIOU:shoot\r\n";
}

/* Concrete */
void Skibbe::tactics(){
    std::cout << "Skibbe:3-6-1\r\n";
}

/* Concrete */
abstract_Manager *Sanfrecce::CreateManager(){
    return new Skibbe();
}

abstract_FW *Sanfrecce::CreatePlayer(){
    return new PIEROS_SOTIRIOU();
}
```

```cpp:Japan.h
#pragma once

/* Concrete */
class Doan : public abstract_FW{
    public:
        void shoot();
        ~Doan(){}
};

/* Concrete */
class Moriyasu : public abstract_Manager{
    public:
        void tactics();
        ~Moriyasu(){}
};

/* Concrete */
class Japan : public soccerteam_Abstractfactory{
    public:
        abstract_FW *CreatePlayer();
        abstract_Manager *CreateManager();
        ~Japan(){}
};
```

```cpp:Japan.cpp
#include <iostream>
#include "Abstract.h"
#include "Japan.h"

/* Concrete */
void Doan::shoot(){
    std::cout << "Doan:shoot\r\n";
}

/* Concrete */
void Moriyasu::tactics(){
    std::cout << "Moriyasu:5-4-1\r\n";
}

/* Concrete */
abstract_Manager *Japan::CreateManager(){
    return new Moriyasu();
}

abstract_FW *Japan::CreatePlayer(){
    return new Doan();
}

```


```cpp:main.cpp

#include <iostream>
#include "Abstract.h"
#include "Sanfrecce.h"
#include "Japan.h"

int main()
{
    int team;
    soccerteam_Abstractfactory *factory;

    std::cout << "Enter team(0:sanfrecce, 1:Japan)";
    std::cin >> team;
 
    switch(team){
        case 0:
            factory = new Sanfrecce();
            break;
        case 1:
            factory = new Japan();
            break;
    }   

    /* ここからは変わらない、具象クラスは意識していない */

    if (factory != NULL){
    abstract_FW * fw = factory->CreatePlayer();
    abstract_Manager * mg = factory->CreateManager();
    
    mg->tactics();
    fw->shoot();
    delete fw;
    delete factory;
    }else{
        std::cerr << "error";
    }

    return 0;
}
```


# 実行結果
```sh
% g++ -o AbstractFactory Sanfrecce.cpp main.cpp Japan.cpp
% ./AbstractFactory 
Enter team(0:sanfrecce, 1:Japan)0
Skibbe:3-6-1
PIEROS_SOTIRIOU:shoot

% ./AbstractFactory
Enter team(0:sanfrecce, 1:Japan)1
Moriyasu:5-4-1
Doan:shoot
```
サンフレッチェの場合は、スキッベ監督の戦術3-6-1と、ピエロスがシュートする、という結果が表示されます。
日本代表の場合は、森保監督の戦術5-4-1と、堂安がシュートする、という結果が表示されます。

# 総括
今回のキモとなる部分は、
抽象クラスであるsoccerteam_Abstractfactory型でインスタンスを生成後は、
具体的なクラスを意識せずに、監督の戦術と、FWのシュートというメソッドが呼び出せていることにあります。

このように、たとえば他のJリーグのチームに置き換えても同じ部品（プレイヤーと監督）であることは変わらないので、今回のデザインパターンが有効であると思いました。

他のデザインパターンでも例を考えて作ってみたいと思います。