デザインパターン_AbstractFactory

## 初めに
:::note warn
この記事は実力不足により，作成途中です．
改善案等がありましたら，是非コメントしてください.
:::

## 参照
[8.AbstractFactoryパターン](https://www.techscore.com/tech/DesignPattern/AbstractFactory)
[実践デザパタ-その2:Factory Methodパターン](https://hamasyou.com/blog/2004/05/31/factory-method/)
[IT専科-Abstract Factory パターン](https://www.itsenka.com/contents/development/designpattern/abstract_factory.html)

### 開発環境
windows10 home
C++20
VisualStudio2019

## AbstractFactoryパターンとは
AbstractFactoryパターンとは，生成に関するデザインパターンの1つで，
Factoryパターンと同様に一連のオブジェクト群を間違いなく生成するためのパターンになっている.

例
> 例えば、「車」を作成するプログラムを考えてみてください。このプログラムのある部分で、
「車」オブジェクトである変数`car`にタイヤとハンドルを追加しています。
`car.addTire(new CarTire());`
`car.addHandle(new CarHandle());`
このプログラムの書き方は、たいていの場合問題ないのですが、プログラマーのふとしたミスで、
とんでもない間違いが起きる可能性があります。例えば、車を作っているのに、
自転車のタイヤを渡してしまうようなことを考えて見ましょう。
`car.addTire(new BicycleTire());`
`car.addHandle(new CarHandle());`
まさか実際に車を作成するときに、このような間違いを犯してしまうことは考えられません。
しかし、利用すべきでないオブジェクトを利用してしまう可能性は大いに考えられます。
このようなとき、車を作成するために必要な一連のオブジェクトを作成することを
一手に引き受ける工場クラスを用意し、タイヤやハンドルといったオブジェクトを生成するときは、
この工場クラスを利用してオブジェクトの生成を行うようにすることで、
先ほどのような間違いが起こることを回避することができます。
また、この工場クラスを変更することで、利用する一連のオブジェクトをごっそり変更することもできるようになります。

[8.AbstractFactoryパターン](https://www.techscore.com/tech/DesignPattern/AbstractFactory)より引用

## メリット
- 変更がしやすくなる
- 複雑な生成処理が分かりやすくなる
- 結合度が低い

## デメリット
> 逆に、Abstract Factoryパターンの欠点は、
関連オブジェクト(先ほどの例だと「ブラウザ」「ファイルシステム」)の種類が増えた場合、
修正箇所がすべてのFactoryクラスに及んでしまう点です。この場合だと、開放・閉鎖原則は守られていません。

[実践デザパタ-その2:Factory Methodパターン](https://hamasyou.com/blog/2004/05/31/factory-method/)より引用

## 処理

### クラス図
![designpattern-abstract_factory01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2736795/ffcc9734-41e4-8cb5-8395-acb3d951f878.gif)
[IT専科-Abstract Factory パターン](https://www.itsenka.com/contents/development/designpattern/abstract_factory.html)より引用

### main
``` C++:main.cpp
#include "AbstractFactory.h"
using namespace std;

int main()
{
    auto factory = std::make_unique<AbstractFactory<ConcreteFactory>>();

    //TODO:ここはメモリの局所性が悪い気がする
    auto product_a = factory->Use()->create_product_a();
    product_a->do_something();

    auto product_b = factory->Use()->create_product_b();
    product_b->do_something();

    return 0;
}
```


### AbstractFactory
``` C++:ConcreteFactory
#pragma once
#include "ConcreteProduct.h"

// Factoryを表すインタフェース
template<class T>
concept FactoryConcept = requires(T obj) {
    {obj.create_product_a()}->std::convertible_to<std::unique_ptr<Product>>;
    {obj.create_product_b()}->std::convertible_to<std::unique_ptr<Product>>;
};


template<FactoryConcept T>
class AbstractFactory
{
public:
    AbstractFactory() {}
    virtual ~AbstractFactory() {};
    std::unique_ptr<T> Use() { return std::make_unique<T>(); }
};


//TODO:AbstractFactoryから派生させたい
class ConcreteFactory
{
public:
    ConcreteFactory() {};
    ~ConcreteFactory() {};
    std::unique_ptr<Product> create_product_a() const
    {
        return std::make_unique<ConcreteProductA>();
    }

    std::unique_ptr<Product> create_product_b() const
    {
        return std::make_unique<ConcreteProductB>();
    }
};
```

### Product
```C++:Product.h
#pragma once

#include <iostream>
#include <memory>
#include <concepts>

class Product
{
public:
    virtual ~Product() = default;
    virtual void do_something() const = 0;
};
```


### ConcreteProduct
```C++:ConcreteProduct.h
#pragma once
#include "Product.h"

class ConcreteProductA : public Product
{
public:
    void do_something() const override
    {
        std::cout << "ConcreteProductA: doing something" << std::endl;
    }
};

class ConcreteProductB : public Product
{
public:
    void do_something() const override
    {
        std::cout << "ConcreteProductB: doing something" << std::endl;
    }
};
```


## 改良したいところ
上記のTODOにもある通り
- 局所性の改善
- ConcreteFactoryをAbstractFactoryから派生するようにしてミスする可能性を減らす
を改良したいです.