質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.06%

[Unity]Singletonとstaticについて

解決済

回答 2

投稿

  • 評価
  • クリップ 1
  • VIEW 6,690

kanade

score 23

こんにちは。以前にもこちらでSingletonとstaticの違いについて教えていただいたのですが、やはりどうしてもわからないことがあるので教えて下さい。
たとえば、マウスの座標を取得するMouseManagerを作成する場合に、

singletonとして

public class MouseManager : MonoBehaviour
{
    // シングルトン =================================================================
    public static MouseManager Instance;
    void Awake()
    {
        if( Instance != null ) Destroy( gameObject );    // すでに存在しているなら削除
        else Instance = this;    // 存在していないなら指定する
        DontDestroyOnLoad( gameObject );    // シーン遷移では破棄させない
    }

    // マウスの座標を取得
    // @return マウスの座標(Vector3)
    public Vector3 MousePos()
    {
        // Vector3でマウスのスクリーン座標を取得する
        Vector3 screenPos = Input.mousePosition;
        // Z軸の修正(メインカメラとオブジェクトの距離)
        screenPos.z = Camera.main.transform.position.z;
        // スクリーン座標をワールド座標に変換
        Vector3 mousePos = Camera.main.ScreenToWorldPoint( screenPos );
        return mousePos;
    }
}
Debug.Log( MouseManager.Instance.MousePos() );


とするのと、staticとして、

public class MouseManager : MonoBehaviour
{
    // マウスの座標を取得
    // @return マウスの座標(Vector3)
    public static Vector3 MousePos()
    {
        // Vector3でマウスのスクリーン座標を取得する
        Vector3 screenPos = Input.mousePosition;
        // Z軸の修正(メインカメラとオブジェクトの距離)
        screenPos.z = Camera.main.transform.position.z;
        // スクリーン座標をワールド座標に変換
        Vector3 mousePos = Camera.main.ScreenToWorldPoint( screenPos );
        return mousePos;
    }
}
Debug.Log( MouseManager.MousePos() );

とするのでは、同じ出力結果を得ることができると思うのですが、調べると、共通の機能をもたせたい場合にはSingletonの使用が推奨されているように感じます。
〜Managerを作りたい時にsingletonを使うべき理由やstaticとの違いについて教えて下さい。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

前者のコード例がSingletonになっていないのですがそれは本題ではないので置いておくことにして。

確かにプログラムを書くだけならstaticメソッドを提供すれば十分と言えます。ではなぜわざわざSingletonでオブジェクトを用意してそれ経由でアクセスさせるか?
キーワードは「疎結合」です。
オブジェクトにするなら、MouseManager.Instance のようにオブジェクトを直接呼ぶ他にも、MouseManager型からinterfaceを抽出しておき、interface型のフィールドで参照しておいてそれを叩くということができます。
interface経由で呼ぶようにすれば「呼ぶ側と呼ばれる側は、使い方だけ知っていてお互いの中身を知らない」状態にできます。
こうすると、修正の影響が他部位に波及しにくくなるとか、ユニットテストするときにダミーのオブジェクトを代わりに渡すとかの効果が得られます。
これが疎結合の考え方です。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/04 01:06

    回答ありがとうございます。
    記述の誤りを指摘してくださりありがとうございました!

    なるほど、「疎結合」ですか。
    シングルトンにはそのような役割もあるのですね!
    回答を拝見して、私はまだまだ未熟だとさらに感じました。

    勉強頑張ります。
    ありがとうございました!

    キャンセル

  • 2016/03/04 09:36

    ここで挙げた疎結合のメリットは大規模開発で活きてくるもので、ホビーの開発にはあまり関係ありません。なのでライブラリの中には、どちらの使い方もできるようにSingletonのメソッドと同名のstaticメソッドも用意してくれているようなのもあります。

    キャンセル

0

こんにちは。

本当にシングルトンとstaticメソッドを比較されていたのですね。ちょっとびっくり。両者は「自転車」と「乳母車」程違うので比較にならないです。これらは使う目的が大きく違うので使い分けに悩むことは滅多にないです。

共通の機能をもたせたい場合にはSingletonの使用が推奨されているように感じます。 

staticメソッドとシングルトンを比較して、どちらでも可能ならシングルトンを使った方がよいと書かれているサイトが複数あったのですか!? 文面の意味を取り違えているということは無いでしょうか?
もし、可能でしたら、そのように書かれているように見えたサイトを幾つか紹介頂けると、何かコメントできるかも知れません。

もしかして、矢沢久雄の早わかりGoFデザインパターン(7)も該当しますか? ここは、staticフィールドと比較してシングルトンは強力って言ってますね。

たとえば、プログラムを実行しているコンピュータやOSなどを表すクラスです。このようなクラスのオブジェクトは、1つだけ作って共有すべきですね。それを実現するのが、Singleton(一人っ子)パターンです。

とも書いてました。
自分のコンピュータだけでなくネットワークに繋がっている他のコンピュータもありますね。折角作ったクラスをそれらにも使いたくなることって本当にないのでしょうか?

シングルトンパターンの誘惑に負けないが参考になると思いますよ。


【追記】
機能的により単純なstaticメソッドで足るのであれば、staticメソッドで実装した方が良い場合がほとんどです。シンプルイズベストです。
メソッドでは機能が足りない時にはクラスで実装し、グローバル変数(他のクラス内のstaticフィールド)でインスタンスを保持すれば良いです。
複数あるとバグの元になるインスタンスを間違ってコピーして使うことが懸念される時は、シングルトン化するのが良いです。

あ、でもそれ以前に本当にグローバル変数が適切なのか?も検討しましょう。
グローバル変数(シングルトンもその一種です。)を無思慮に使うとやはりはまります。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/08 23:04

    なるほど…
    ありがとうございます!

    キャンセル

  • 2016/03/08 23:49

    kanadeさん。

    すいません、前回のコメントに今気が付きました。

    http://naichilab.blogspot.jp/2013/12/unity.html
    http://kan-kikuchi.hatenablog.com/entry/AudioManager2

    この2つは同じこと書いてますね。「どこからでも呼び出せると便利で、でも2つ以上あったら変なもの。」
    間違いです。「どこからでも呼び出せる必要があるもので、2つ以上あったらダメなもの」です。要するに安易にシングルトン化するのは間違いです。

    http://hiroaki-kono.hatenablog.com/entry/2014/05/04/135130

    確かにstaticなクラスとシングルトンを比較してますね。
    選択時の第一候補が漏れてます。普通のクラスです。このページの主旨ではないのでしかたがないかも知れません。よく分かってないから自分なりに纏めてみたという位置づけのようですし。

    全ての場所からアクセスしたいだけなら、グローバルなインスタンスにするだけです。staticクラスに「全ての場所からアクセスしたいクラスのインスタンス」を入れればばそうなります。

    普通のクラスをグローバルなインスタンスにしたものは、もし、複数のインスタンスが必要なら、その必要性に応じて別のグローバルなインスタンスを作るなり、他のクラス内のメンバにするなり、自由にできます。シングルトンはそれをできないようにしたものです。
    その制限がありがたいことがあるので有用なのです。そのありがたみを理解しないまま使うのは誤りです。

    キャンセル

  • 2016/03/16 20:54

    返信ありがとうございます。
    おかげさまで両者が全く別々のものであるということを理解することができました。
    本当にありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.06%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る