SPARKCREATIVE Tech Blog

https://www.spark-creative.jp/

Re:ゼロから始めるUniRx 1話

f:id:spark-hosoi-koyo:20210227172512p:plain
こんにちは、クライアントエンジニアの細井です。
今回から数回に渡ってUniRxについての記事を書いていこうと思います。

UniRxとは

リアクティブプログラミングの考え方をUnityで利用するためのライブラリになります。
※リアクティブプログラミング
「ボタンが押された」の様なイベントが発生したら何かの処理をするというように
特定のイベントに反応するプログラミングを容易に実現するための概念のようなもの

メリット
  • コードを簡略化出来る
  • 書き方が統一される
  • Rxの概念はほかの言語などでも有用
デメリット
  • 正しく使わないとコードを複雑化させてしまう
  • 機能が多く複雑なため学習コストが高い


おそらくUniRxの導入で一番のネックになるのは”機能が多く複雑なため学習コストが高い”
この部分かと思います。
UniRxとはどういうものなのかゼロから学んで、理解しながら使用出来るよう
一緒に勉強していきましょう!

UniRxとObserverパターン

いきなりUniRx以外の話になりますが、
UniRxはObseverパターンを基礎に作られており、きちんと理解するうえでは外せない項目です。

Observerパターンとは
  • GoFデザインパターンのひとつ
  • オブジェクトのイベントを他のオブジェクトに通知する処理で使用される

観察者(Observer)と観察される対象(Subject)が存在し、
Subjectの状態が変化した際にObserverに通知されるという流れになります。
しかし、この説明は形式的過ぎて理解しずらいです。

学校の先生がObserver、生徒がSubjectだとしたらどうでしょう。
地域の清掃というイベントがあり、生徒は拾ったごみの量で景品がもらえます。
しかし先生が一人一人に拾ったごみの量を聞いて回るのは手間がかかり効率が悪いです。
そこで生徒が自ら拾ったごみの量を先生に報告することにしました。
その結果、先生は待っているだけで生徒のごみの量がわかるようになりました。
めでたしめでたし。
この関係性がObserverパターンで行われることになります。

コードでみてみよう

後々UniRxを使うので今回はC#を使用
Observerのインターフェイス

public interface IObserver {
    void update(Subject subject);
}

観察対象が継承するための抽象クラス
通知するためにAdd関数でObserverを登録しています。
Listになっている事で複数の観察者に通知を送ることが出来ます。
また、例題の状況を再現するために名前を返すGetName、
拾ったごみの数を返すGetNumを用意しておきます。

public abstract class Subject
{
    private List<IObserver> _observers = new List<IObserver>();

    public void Add(IObserver observer)
    {
        _observers.Add(observer);
    }

    public void NotifyObservers()
    {
        _observers.ForEach(observer => observer.Update(this));
    }

    public abstract string GetName();
    public abstract int GetNum();
    public abstract void Report();
}

インターフェースを使用し先生を作成

public class Teacher1 : IObserver
{
    public void Update(Subject subject)
    {
        var name = subject.GetName();
        var num = subject.GetNum();
        System.Diagnostics.Debug.WriteLine($"{name}さんが拾ったゴミの数 : {num}") ;
    }
}

Subjectクラスを継承し生徒を作成
Report関数内でNotifyObserversを呼ぶことで通知を行うようにしました。

public class Student1 : Subject
{
    string _name = "太郎";
    int _num = 10;

    public override string GetName()
    {
        return _name;
    }

    public override int GetNum()
    {
        return _num;
    }

    public override void Report()
    {
        NotifyObservers();
    }
}

もう一人生徒を作成

public class Student2 : Subject
{
    string _name = "次郎";
    int _num = 5;

    public override string GetName()
    {
        return _name;
    }

    public override int GetNum()
    {
        return _num;
    }

    public override void Report()
    {
        NotifyObservers();
    }
}

生徒に報告する対象の先生を登録し、Reportで報告させる

class Program
{
    static void Main(string[] args)
    {
        Teacher1 teacher = new Teacher1();
        Subject student1 = new Student1();
        Subject student2 = new Student2();

        student1.Add(teacher);
        student2.Add(teacher);

        student1.Report();
        student2.Report();
    }
}

出力結果
f:id:spark-hosoi-koyo:20210227172523p:plain

ここまでが最小単位のObserverパターンになります。
実際に手を動かして書いてみると簡単に理解できるはずです。
このような設計にする事でObserver、Subjectを自由に増やすことが出来るようになっていますね。

おわりに

今回はここまでになります。
UniRxとは・・・という内容になってしまいましたが、今回勉強したObserverパターンがどのように
UniRxへ変化していくのか次回からが本編です。