LoginSignup
1
2

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

Posted at

やりたいこと

関数実行時の前提条件を追加したい。

bool EnZentei //前提条件

void HogeFunc()
{
}
if(Enzentei){
    HogeFunc()
}

これをスマートに実装したい。

言いたいことまとめ

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

選択肢1 ifですべて囲う

if(Enzentei){
    HogeFunc()
}

メリット:わかりやすい
デメリット:変更箇所が増える。条件追加するときすべて変更しないといけない

条件の関数化

条件を内包する関数を作成

bool EnzenteiFunc(){
    if(EnZentei)
    {
        retrun true
    }
    else
    {
        retrun false
    }
}

使用箇所

if(EnzenteiFunc()){
    HogeFunc()
}

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

選択肢2 デコレートパターン

デリゲートを使いヘルパー関数にて実行させる。

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 => { });
});

使用例その2

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

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

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

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

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

選択肢3 アクションデリゲート使った実装

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();

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

選択肢4 ラッパー関数を用いた条件付きメソッドの実行

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(); // 何もしない

メリット:
デメリット:

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

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(); // 何も出力されない

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

選択肢6 デリゲートを用いた柔軟な条件の変更

条件部分を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();
}

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

選択肢7 テンプレートパターン

クラスの継承を使用して、親クラスで関数呼び出し時に必ず呼ばれる関数を実装する

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(); // 何も実行されない
    }
}

メリット:テンプレートメソッドを親クラスに定義することで、共通の処理フローを複数のサブクラスで再利用できる
デメリット:ファイルが別になり、複雑度が上がる。

感想

実装一つにしてもいろいろあるね!

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2