ここぷろ!

私がプログラミングで学んだこと、行き詰った事などを書いていきます。たまに個人的なことも載せるかも

任意のInterfaceを実装したクラスを取得するメソッドを実装しました


 こんにちは、ここあです。


 前回、インタフェース活用例でちらっとお話した、自前の拡張メソッドを紹介したいと思います。
 これに関しては、前回の記事で紹介したものと違い、インタフェースについて調べてるときにどこかで見た気がしますが……?
 もしかしたら誰かが同じような実装をしているかもしれませんが、備忘録として書いておこうと思います。

実装詳細

きっかけ

 今回紹介するメソッドですが、複数シーンを同時に運用している関係上、各シーンごとのオブジェクトを、各管理クラスが明確に把握した状態で運用できるように、考えた結果行きついた答えのひとつです。これを関数の呼び出しのみで行いたかった為に実装しました。


 前回の記事Unityゲーム開発で役立つインタフェース活用例 - ここぷろ!で紹介した通り、拡張メソッドになります。
 ジェネリクスを使い、任意のインタフェースを実装した、全てのクラスを取得してくる拡張メソッドです。


 ジェネリクスについて、私はこちらのサイトを参考に勉強させていただきました。 
ufcpp.net

処理手順

 基本的にシーンが生成された直後のAwake()のタイミングで動かすことを前提として作っています。


  1. まず、存在する全てのコンポーネントがアタッチされたオブジェクトを取得。
  2. as演算子により、指定のインタフェースにアップキャストできるか判定。
  3. ゲーム動作中のメモリを少しでも確保するために、念のため可変長のListから、固定長配列に格納して返しています。


 このメソッドは、Manager等の管理クラスから呼ばれることになる為、使いやすさを考慮してstaticメソッドとして定義しました。
 使用する場合は、以下の様に一行の関数呼び出しで使えるようになっています。

// 格納配列変数宣言
private IMasterObj[] masterObjArray;

// オブジェクト取得
var masterObjArray = InterfaceUtils.FindObjectOfInterfaces<IMasterObject>();

 

実装コード

using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Interface便利クラス
/// </summary>
public class InterfaceUtils
{
    /// <summary>
    /// 特定のインタフェースがアタッチされたオブジェクトを見つける
    /// </summary>
    /// <typeparam name="T"> 探索するインタフェース </typeparam>
    /// <returns> 取得したクラス配列 </returns>
    public static T[] FindObjectOfInterfaces<T>() where T : class
    {
        List<T> findList = new List<T>();

        // オブジェクトを探索し、リストに格納
        foreach (var component in GameObject.FindObjectsOfType<Component>())
        {
            var obj = component as T;

            if (obj == null) continue;

            findList.Add(obj);
        }

        T[] findObjArray = new T[findList.Count];
        int count = 0;

        // 取得したオブジェクトを指定したインタフェース型配列に格納
        foreach (T obj in findList)
        {
            findObjArray[count] = obj;
            count++;
        }
        return findObjArray;
    }
}

終わりに

 使う場面は限られるかもしれませんが、ある程度の一括管理などをしている場合には、結構いい感じに使えるんじゃないかなと思います。
 私の場合は特にUpdateも、なるべくUnity本来のコールバックを使用しない形での実装を目指しているので、重宝しています。


 まだ改善できる箇所があるような気がしているので、よりよい実装があれば教えて頂けるとありがたいです。


 それでは、今回はこの辺りで。