こんにちは、むたこなです。
GetComponentを使ってコンポーネントを取得する際に以下のようなお悩みはありませんか?
- 取得するコンポーネントの種類がたくさんあって参照するのが面倒…
- たくさんの種類を参照する割に実行するのは初期化処理1つだけ…
- 状況によって取得できるコンポーネントが分からない…
この記事では、Interfaceを使ってこれらのお悩みを解決したいと思います。
上記の悩みに共感する方や心当たりのある方は是非ご覧ください。
InterfaceをGetComponentで取得する
まずは、実際の使い方をご紹介します。
状況は、「初期化メソッドInitializeを各コンポーネントクラスに実装しており、
Start時にそれらを実行したい」ということにします。
各コンポーネントのStartでInitializeを実行すればいいじゃんというのは無しです(泣)
何らかの理由でコンポーネントを束ねるクラスが初期化をしなくてはいけない事としてください…!
以下のようなInterfaceを用意します。
public interface IInitializable
{
public void Initialize();
}
続いて、各コンポーネントクラスにこのInterfaceを実装します。
public class Component1 : MonoBehaviour, IInitializable
{
public void Initialize()
{
Debug.Log("Initialized");
}
}
最後にGetComponentを使ってコンポーネントを取得します。
なお、ここでは複数の子オブジェクトに該当のコンポーネントが
アタッチされた状況だと想定します。
private void Start()
{
foreach (Transform child in this.transform)
{
var initializable = child.GetComponent<IInitializable>();
initializable.Initialize();
}
}
以上が流れです。
スマートに書けたのではないでしょうか?
Interfaceを使わないと?
先ほどの例を、Interfaceを使わずに実装した場合どのようになるか考えてみました。
各コンポーネントにはそれぞれInitializeというメソッドを用意している想定です。
private void Start()
{
foreach (Transform child in this.transform)
{
if (child.TryGetComponent<Component1>(out var componen1))
{
componen1.Initialize();
}
else if (child.TryGetComponent<Component2>(out var component2))
{
component2.Initialize();
}
else if (child.TryGetComponent<Component3>(out var component3))
{
component3.Initialize();
}
}
}
先ほどと比較して、かなり行が増えてしまいました。
しかも、このコードは新しいコンポーネントを増やそうとすると、
新しく書き加える必要があり非常に拡張性が悪いです。
まとめ
いかがでしょうか?
Interfaceを使ってGetComponentをすると参照するコンポーネントを特定しないので、
条件分岐が不要になりコードがスマートに書けました。
今回はGetComponentを題材に記事を書きましたが、
同じような状況であればGetComponentを使わずとも、
Interfaceは活躍すると思います。
積極的に利用してオブジェクト指向に小慣れた感を出しましょう!!
コメント