やりたいこと
関数実行時の前提条件を追加したい。
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(); // 何も実行されない
}
}
メリット:テンプレートメソッドを親クラスに定義することで、共通の処理フローを複数のサブクラスで再利用できる
デメリット:ファイルが別になり、複雑度が上がる。
感想
実装一つにしてもいろいろあるね!