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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

2回答

11632閲覧

[Unity]Singletonとstaticについて

kanade

総合スコア23

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

1クリップ

投稿2016/03/03 09:18

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

singletonとして

C#

1public class MouseManager : MonoBehaviour 2{ 3 // シングルトン ================================================================= 4 public static MouseManager Instance; 5 void Awake() 6 { 7 if( Instance != null ) Destroy( gameObject ); // すでに存在しているなら削除 8 else Instance = this; // 存在していないなら指定する 9 DontDestroyOnLoad( gameObject ); // シーン遷移では破棄させない 10 } 11 12 // マウスの座標を取得 13 // @return マウスの座標(Vector3) 14 public Vector3 MousePos() 15 { 16 // Vector3でマウスのスクリーン座標を取得する 17 Vector3 screenPos = Input.mousePosition; 18 // Z軸の修正(メインカメラとオブジェクトの距離) 19 screenPos.z = Camera.main.transform.position.z; 20 // スクリーン座標をワールド座標に変換 21 Vector3 mousePos = Camera.main.ScreenToWorldPoint( screenPos ); 22 return mousePos; 23 } 24}

C#

1Debug.Log( MouseManager.Instance.MousePos() );

とするのと、staticとして、

C#

1public class MouseManager : MonoBehaviour 2{ 3 // マウスの座標を取得 4 // @return マウスの座標(Vector3) 5 public static Vector3 MousePos() 6 { 7 // Vector3でマウスのスクリーン座標を取得する 8 Vector3 screenPos = Input.mousePosition; 9 // Z軸の修正(メインカメラとオブジェクトの距離) 10 screenPos.z = Camera.main.transform.position.z; 11 // スクリーン座標をワールド座標に変換 12 Vector3 mousePos = Camera.main.ScreenToWorldPoint( screenPos ); 13 return mousePos; 14 } 15}

C#

1Debug.Log( MouseManager.MousePos() );

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

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

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

投稿2016/03/03 09:58

yuba

総合スコア5568

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kanade

2016/03/03 16:06

回答ありがとうございます。 記述の誤りを指摘してくださりありがとうございました! なるほど、「疎結合」ですか。 シングルトンにはそのような役割もあるのですね! 回答を拝見して、私はまだまだ未熟だとさらに感じました。 勉強頑張ります。 ありがとうございました!
yuba

2016/03/04 00:36

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

0

こんにちは。

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

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

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

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

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

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

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


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

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

投稿2016/03/03 12:19

編集2016/03/03 14:14
Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kanade

2016/03/03 16:01

こんばんは。 またご回答くださりありがとうございます! 感激です! 私はまだプログラミング歴が浅く、突拍子も無い質問をしてしまい申し訳ありません。 シングルトンについてですが、まず、Unityで「シーン遷移時のフェードイン・フェードアウト」の実装の仕方について調べていたら、 http://naichilab.blogspot.jp/2013/12/unity.html にてシングルトンを使うことを勧められていたためシングルトンを使いました。 また、音声を扱うことについて、 http://kan-kikuchi.hatenablog.com/entry/AudioManager2 にてシングルトンを扱うことで、音声を簡単に扱うことができるようになるということがわかりました。 加えて、シングルトンについて調べていて見つけた、 http://hiroaki-kono.hatenablog.com/entry/2014/05/04/135130 を読み、Singletonなクラスとstaticなクラスでは同じようなことが可能であると感じました。 と、ここまで書いていて思ったのですが、ひょっとしてUnityは、すべてのスクリプトにMonoBehaviourを継承させる必要があるために、staticなクラスを作成することができず、しかたなくSingletonなクラスを使用しているふしがあるのでしょうか。 私の中でも曖昧で、おかしな質問となってしまっていたら申し訳ありません。 お願いいたします。
yuba

2016/03/04 00:34

> すべてのスクリプトにMonoBehaviourを継承させる必要があるために、staticなクラスを作成することができず、しかたなくSingletonなクラスを使用している 私の回答の方で書きませんでしたが、こういう目的もSingletonを採用する理由になります。はい。
kanade

2016/03/08 14:04

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

2016/03/08 14: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クラスに「全ての場所からアクセスしたいクラスのインスタンス」を入れればばそうなります。 普通のクラスをグローバルなインスタンスにしたものは、もし、複数のインスタンスが必要なら、その必要性に応じて別のグローバルなインスタンスを作るなり、他のクラス内のメンバにするなり、自由にできます。シングルトンはそれをできないようにしたものです。 その制限がありがたいことがあるので有用なのです。そのありがたみを理解しないまま使うのは誤りです。
kanade

2016/03/16 11:54

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問