Visual Studio 2019 で Abstract Factory を作ってみる

新しくなった Visual Studio 2019 で気になったことを書きながら GoF デザインパターンの Abstract Factory を作ってみます。

- 新機能は [Visual Studio 2019 の新機能 | Microsoft Docs](https://docs.microsoft.com/ja-jp/visualstudio/ide/whats-new-visual-studio-2019?view=vs-2019) に記載されています
  - もっと詳しい情報は [Visual Studio 2019 リリース ノート | Microsoft Docs](https://docs.microsoft.com/ja-jp/visualstudio/releases/2019/release-notes#csharp-defaults) に記載されています
- 各エディションは [Visual Studio 製品の比較 | Visual Studio](https://visualstudio.microsoft.com/ja/vs/compare/) に記載されています
- GoF デザインパターンは [.NET Design Patterns in C# and VB.NET - Gang of Four (GOF) - doFactory.com](https://www.dofactory.com/net/design-patterns) からの引用になります
- 書籍からデザインパターンを学びたい場合は結城浩の [増補改訂版 Java 言語で学ぶデザインパターン入門](https://www.hyuki.com/dp/) がおすすめです

## 気になったこと

- C# 8.0 は (デフォルト状態だと) まだです
  - .NET Core 3.0 もまだです
  - プロジェクトの LangVersion を自分で変更するか、 .NET Core 3.0 プレビューを使用すれば使えるようになります
  - リリースに備えて [C# 8.0 の新機能 - C# によるプログラミング入門 | ++C++; // 未確認飛行 C](https://ufcpp.net/study/csharp/cheatsheet/ap_ver8/) で勉強しましょう
- 色んな新しいプロジェクトを作るときに .NET Core を優先するようになりました
  - 2017 の頃から思っていたことで、 Windows の GUI アプリじゃない限り .NET Framework は使わなくてもよい考えが加速しました
- Community と Professional が殆ど同じものになりました
  - CodeLens が Community 版でも使用できるようになっています
  - ただし Community 版のライセンス条項は 2017 と変わらないので、エンタープライズの人達はきちんと買ってね ♡
- Ctrl+Q (新しい検索エクスペリエンス) はとても便利になりました
  - 2017 のときはワンテンポ遅くてどうしても使いづらかったのですが、爆速になっています
- Ctrl+. がパワーアップしました。それと未使用の変数とかも教えてくれるようになりました (これは 2017 から？)
  - でもやっぱり ReSharper (Alt+Enter) のほうが頭がよいので ReSharper を入れたほうがよいです
- if とか for とかの statement とか method の色が変わりました
  - 2017 のときは string とか int の基本型と同じ青色だったり、普通の黒色でした
  - Color theme (Blue) は 2017 より全体的に薄いので、白文字が少し見づらくなっています

## GoF デザインパターン - Abstract Factory

簡単なコンソールアプリのコードを書いても 2017 からの進化はよくわかりませんでした。

### UML class diagram

[![Image from Gyazo](https://i.gyazo.com/e00735da7b09c43595583f408b359524.png)](https://gyazo.com/e00735da7b09c43595583f408b359524)

### Output

[![Image from Gyazo](https://i.gyazo.com/f19d4e85c1148c1c02e6c1bdc99d0c9e.png)](https://gyazo.com/f19d4e85c1148c1c02e6c1bdc99d0c9e)

### Code

```csharp:Program.cs
class Program
{
    static void Main(string[] args)
    {
        AbstractFactory factory1 = new ConcreteFactory1();
        var client1 = new Client(factory1);
        client1.Run();

        AbstractFactory factory2 = new ConcreteFactory2();
        var client2 = new Client(factory2);
        client2.Run();
    }
}
```

```csharp:AbstractFactory.cs
abstract class AbstractFactory
{
    public abstract AbstractProductA CreateProductA();
    public abstract AbstractProductB CreateProductB();
}
```

```csharp:ConcreteFactory1.cs
class ConcreteFactory1 : AbstractFactory
{
    public override AbstractProductA CreateProductA()
    {
        return new ProductA1();
    }
    public override AbstractProductB CreateProductB()
    {
        return new ProductB1();
    }
}
```

```csharp:ConcreteFactory2.cs
class ConcreteFactory2 : AbstractFactory
{
    public override AbstractProductA CreateProductA()
    {
        return new ProductA2();
    }
    public override AbstractProductB CreateProductB()
    {
        return new ProductB2();
    }
}
```

```csharp:AbstractProductA.cs
abstract class AbstractProductA
{
}
```

```csharp:AbstractProductB.cs
abstract class AbstractProductB
{
    public abstract void Interact(AbstractProductA a);
}
```

```csharp:ProductA1.cs
class ProductA1 : AbstractProductA
{
}
```

```csharp:ProductA2.cs
class ProductA2 : AbstractProductA
{
}
```

```csharp:ProductB1.cs
class ProductB1 : AbstractProductB
{
    public override void Interact(AbstractProductA a)
    {
        Console.WriteLine($"{GetType().Name} interacts with {a.GetType().Name}");
    }
}
```

```csharp:ProductB2.cs
class ProductB2 : AbstractProductB
{
    public override void Interact(AbstractProductA a)
    {
        Console.WriteLine($"{GetType().Name} interacts with {a.GetType().Name}");
    }
}
```

```csharp:Client.cs
class Client
{
    private readonly AbstractProductA _abstractProductA;
    private readonly AbstractProductB _abstractProductB;

    public Client(AbstractFactory factory)
    {
        _abstractProductB = factory.CreateProductB();
        _abstractProductA = factory.CreateProductA();
    }

    public void Run()
    {
        _abstractProductB.Interact(_abstractProductA);
    }
}
```