C# 前提条件を追加する方法の選択肢

## やりたいこと
関数実行時の前提条件を追加したい。
```
bool EnZentei　//前提条件

void HogeFunc()
{
}
```
```
if(Enzentei){
    HogeFunc()
}
```
これをスマートに実装したい。

## 言いたいことまとめ
まずはifで実装しよう！
それがだめならデコレートパターンかな。
そして条件と実行の柔軟性が必ず必要なときだけ
デリゲートを使った。関数Listでの実行をするといいと思う。
だいたい複雑度がましてるね。

## 選択肢１　ifですべて囲う
```
if(Enzentei){
    HogeFunc()
}
```
メリット：わかりやすい
デメリット：変更箇所が増える。条件追加するときすべて変更しないといけない
## 条件の関数化
条件を内包する関数を作成
```
bool EnzenteiFunc(){
    if(EnZentei)
    {
        retrun true
    }
    else
    {
        retrun false
    }
}
```
使用箇所
```
if(EnzenteiFunc()){
    HogeFunc()
}
```

メリット：わかりやすい、条件の変更がまとまる。
デメリット：変更箇所が増える。

## 選択肢２ デコレートパターン
デリゲートを使いヘルパー関数にて実行させる。
```
using GoogleMobileAds.Api;
using System;

public class AdsHelper
{
    // 条件に基づいて関数を実行するヘルパー関数
    public static void ExecuteIfEnabled(bool isEnabled, Action action)
    {
        if (isEnabled)
        {
            action();
        }
    }
}

```
使用箇所
```
// 広告が有効な場合にのみ初期化する
AdsHelper.ExecuteIfEnabled(enAds, () =>
{
    MobileAds.Initialize(initStatus => { });
});

```
使用例その２
```
bool EnZentei = true; // この値は動的に変更されるかもしれません

void HogeFunc()
{
    Console.WriteLine("HogeFuncが実行されました。");
}

// 条件とアクションを引数に取るヘルパーメソッド
void ExecuteIfConditionMet(bool condition, Action action)
{
    if (condition)
    {
        action();
    }
}

// ヘルパーメソッドを使って条件チェックと関数の呼び出しを行う
ExecuteIfConditionMet(EnZentei, HogeFunc);

```

メリット：条件の追加容易になる
デメリット：ifとコード変更量はあまりかわらない。複雑さが増す

## 選択肢３ アクションデリゲート使った実装
```
using System;

public class ConditionalExecutor
{
    private Func<bool> _condition;
    private Action _action;

    public ConditionalExecutor(Func<bool> condition, Action action)
    {
        _condition = condition;
        _action = action;
    }

    public void Execute()
    {
        if (_condition())
        {
            _action();
        }
    }
}

```
使用箇所
```
bool enAds = true; // これはどこかで設定される広告を有効にするフラグ

// 広告初期化アクションを定義
Action initializeAdsAction = () => MobileAds.Initialize(initStatus => { });

// 条件付きでアクションを実行するExecutorを作成
ConditionalExecutor executor = new ConditionalExecutor(() => enAds, initializeAdsAction);

// 実行
executor.Execute();

```


メリット：実行するアクションと条件チェックを柔軟に組み合わせられる。
デメリット：複雑度がます

## 選択肢４ ラッパー関数を用いた条件付きメソッドの実行
```
public class AdsManager
{
    private bool enAds;

    public AdsManager(bool enableAds)
    {
        this.enAds = enableAds;
    }

    private void InitializeAds()
    {
        // 実際の広告初期化ロジック
        MobileAds.Initialize(initStatus => { });
        Console.WriteLine("Ads Initialized");
    }

    public void TryInitializeAds()
    {
        if (this.enAds)
        {
            InitializeAds();
        }
        else
        {
            Console.WriteLine("Ads are disabled. Skipping initialization.");
        }
    }
}
```
使用箇所
```
var adsManager = new AdsManager(true); // 広告を有効にする
adsManager.TryInitializeAds(); // 広告が有効なら初期化を試みる

var adsManagerDisabled = new AdsManager(false); // 広告を無効にする
adsManagerDisabled.TryInitializeAds(); // 何もしない

```


メリット：
デメリット：


## 選択肢５ イベントベースの実装

```
using System;

public class AdsManager
{
    public event Action AdEvent;
    private bool enAds;

    public AdsManager(bool enableAds)
    {
        this.enAds = enableAds;
        AdEvent += OnAdEventTriggered;
    }

    public void TriggerAdInitialization()
    {
        AdEvent?.Invoke();
    }

    private void OnAdEventTriggered()
    {
        if (this.enAds)
        {
            InitializeAds();
        }
    }

    private void InitializeAds()
    {
        // 実際の広告初期化ロジック
        Console.WriteLine("Initializing ads...");
    }
}

```
使用箇所
```
var adsManager = new AdsManager(true);
adsManager.TriggerAdInitialization(); // "Initializing ads..."が出力される

var adsManagerDisabled = new AdsManager(false);
adsManagerDisabled.TriggerAdInitialization(); // 何も出力されない

```

メリット：処理の実行タイミングを柔軟にコントロールできる。イベントハンドラを動的に追加・削除することで、実行条件を動的に変更できる。
デメリット：複雑

## 選択肢６　デリゲートを用いた柔軟な条件の変更
条件部分をList化した関数を実行しすべての戻り値がtrueであった場合実行する。

```
using System;
using System.Collections.Generic;

public class ConditionalExecutor
{
    private List<Func<bool>> conditions = new List<Func<bool>>();
    private Action action;

    public ConditionalExecutor(Action action)
    {
        this.action = action;
    }

    public void AddCondition(Func<bool> condition)
    {
        conditions.Add(condition);
    }

    public void Execute()
    {
        foreach (var condition in conditions)
        {
            // 条件の一つでもfalseが返された場合、アクションを実行せずにメソッドを終了する
            if (!condition())
            {
                return;
            }
        }

        // すべての条件がtrueの場合のみ、アクションを実行
        action();
    }
}

```
使用箇所
```
void Main()
{
    // アクションの定義: 広告の初期化を行う
    Action initializeAds = () => Console.WriteLine("Ads Initialized");

    // ConditionalExecutorのインスタンスを作成し、アクションを設定
    var executor = new ConditionalExecutor(initializeAds);

    // 条件1: ユーザーが広告表示を許可している
    bool userAllowsAds = true; // この値は実際のアプリケーションロジックに基づいて変わります
    executor.AddCondition(() => userAllowsAds);

    // 条件2: インターネット接続が利用可能
    bool isConnectedToInternet = true; // この値も実際の状況に基づいて変わります
    executor.AddCondition(() => isConnectedToInternet);

    // 条件を満たす場合のみアクションを実行
    executor.Execute();
}

```
メリット：すべてが柔軟
デメリット：くそわかりずらい

## 選択肢７　テンプレートパターン
クラスの継承を使用して、親クラスで関数呼び出し時に必ず呼ばれる関数を実装する
```
public abstract class BaseClass
{
    // 前提条件
    public bool EnZentei { get; set; }

    // コンストラクタ
    protected BaseClass(bool enZentei)
    {
        EnZentei = enZentei;
    }

    // テンプレートメソッド
    public void ExecuteIfConditionMet()
    {
        if (EnZentei)
        {
            HogeFunc();
        }
    }

    // サブクラスで実装される具体的な処理
    protected abstract void HogeFunc();
}

```
使用箇所
```
public class DerivedClass : BaseClass
{
    // コンストラクタ
    public DerivedClass(bool enZentei) : base(enZentei)
    {
    }

    // HogeFuncの具体的な実装
    protected override void HogeFunc()
    {
        Console.WriteLine("HogeFuncが実行されました。");
    }
}
class Program
{
    static void Main(string[] args)
    {
        // 前提条件を満たす場合
        var instanceTrue = new DerivedClass(true);
        instanceTrue.ExecuteIfConditionMet(); // HogeFuncが実行される

        // 前提条件を満たさない場合
        var instanceFalse = new DerivedClass(false);
        instanceFalse.ExecuteIfConditionMet(); // 何も実行されない
    }
}
```
メリット：テンプレートメソッドを親クラスに定義することで、共通の処理フローを複数のサブクラスで再利用できる
デメリット：ファイルが別になり、複雑度が上がる。
## 感想
実装一つにしてもいろいろあるね！