14

オブジェクトとしてクラスを使用することはできないことを目的の C でシングルトン パターンを採用する必要がある場合 (たとえば、専用クラスを定義して単一のインスタンスを作成する場合) を疑問に思っていました。

特に、次の解決策を考えています。

  1. シングルトン インスタンスのインスタンス メソッドではなく、適切なクラス メソッドを定義して使用します。
  2. staticシングルトン インスタンスのインスタンス変数の代わりに、変数 (ファイル スコープ グローバル) を使用します。
  3. シングルトン インスタンスの代わりに、通知のオブザーバーとして登録するときにクラス オブジェクトを使用します。クラス オブジェクトはそれ自体が目的の C オブジェクトですが (そうですか?)、登録されている通知ハンドラーがクラス メソッドである必要があります。(これは可能ですか?)

たとえば、Textureクラス (モデル オブジェクト)シングルトン (リソース マネージャー) を使用する代わりに、TextureManagerすべてのテクスチャの作成/クリーンアップをクラス メソッドとして実装し、同じTextureクラスの静的変数 (ファクトリ パターンとリソース管理) を使用することができます。

このデザインについて何か考えはありますか?

編集: 考えてみると、Texture上記の例でも、2 つのクラスを分離したまま (TextureTextureManager)、A のいずれかを選択する必要があります。マネージャーをシングルトンにして、インスタンス メソッドで操作するか、B.マネージャーをインスタンスのない補助クラスにする。明確にするために:

Texture* myTexture = [[TextureManager defaultManager] textureWithName:@"TextureName"]; 
// (singleton, client uses instance methods)

Texture* myTexture = [TextureManager textureWithName:@"TextureName"]; 
// (Class standing in for singleton, client uses class methods)

後者はより簡単で、面倒/冗長ではないように見えますが、どちらの設計が「より正しい」のだろうかと思います。もちろん、前者TextureManagerは必要に応じて複数のインスタンスを許可します(私の場合ではありません)。

4

3 に答える 3

7

私も同じことを考えていて、あなたに答えがあると思います。

それはあなたがそれをどうする必要があるかによって異なります。どちらも必ずしもより「正しい」わけではありません。

私の結論に至った経緯の詳細が必要な場合は、読み進めるか、tl;drセクションまでスクロールしてください。

あなたが言ったように、クラスにシングルトンを管理させるためにシングルトンにアクセスする方が(外部的に)面倒ではないように見えます。基本的に、シングルトンのファクトリ メソッドを初期化メソッドに置き換えることでこれを行います。これに関するApple のドキュメントを見ると、要求に応じてシングルトンを生成するファクトリとして機能する「共有」メソッドがどこに示されているかがわかります。

static MyGizmoClass *sharedGizmoManager = nil;

+ (MyGizmoClass*)sharedManager
{
    if (sharedGizmoManager == nil) {
        sharedGizmoManager = [[super allocWithZone:NULL] init];
    }
    return sharedGizmoManager;
}

これを行う代わりに、次のようにメソッドを void 初期化子に置き換えることができます。

+ (void)initializeMyGizmo
{
    if (sharedGizmoManager == nil) {
        sharedGizmoManager = [[super allocWithZone:NULL] init];
    }
    // whatever else needs to be done to the singleton to initialize it
}

そして、クラスメソッドのみを使用MyGizmoClassし、シングルトンのような更新を管理できるようにします[MyGizmoClass setGizmoName:@"Gadget"]

注:このシナリオではファイルを見てプロパティを確認するのは混乱を招く.h可能性があります。その場合、オブジェクト自体のインスタンスを作成するか、一部のシングルトンにアクセスできるようにする必要があるという結論に達する可能性があります。フォームまたはファッション。そのため、シングルトンへのアクセスをカプセル化するルートに進む場合、パブリック変数を使用するのは賢明ではありません。

その時点まで:

クラス自体を介してのみアクセスを制限すると、プロパティに付随するゲッターとセッター、またはその他の無料のものを失います。これは、MyGizmoClassモデルの一部として持つ場合NSString *gizmoName、この「プロパティ」のカスタムゲッターとセッターを作成し、それを ivar またはプロパティのいずれかとして保持する必要があることを意味します.m。シングルトン クラス、または隣接する静的変数として。

したがって、これは疑問を投げかけます (そして、最初に考えさせられたのは)、行static MyGizmoClass *sharedGizmoManager = nil;を含めるか、内部インターフェイス拡張を完全に削除して、アクセスを制限したい可能性のある ivar またはプロパティを置き換えることができるかということです。static実装中の実装?

もう答えたけど…

それはあなたがそれをどうする必要があるかによって異なります。

tl;dr

最初のシナリオ

もしあなたが (ほんのわずかな可能性でさえも) サブクラス化する必要がある場合、 TextureManagerまたはそのインスタンスを複数作成する可能性がある場合 (シングルトンではなくなります)、通常の Apple のシングルトン規則に固執することをお勧めします。

これには複数の「シングルトン」が含ま TextureManagerれ、異なる設定で事前構成された複数の があります。

この場合、必要に応じて (パブリックまたはプライベートに) プロパティと ivar を使用します。ivar と static を組み合わせて使用​​することもできますが、実装TextureManagerの内部には常に静的インスタンスが必要です。TextureManager

第二のシナリオ

の 1つのインスタンスのみが必要であり、それが完全にスタンドアロンで実行され、それ以上混在することがない場合は、ファイル内の実装内のクラスの静的インスタンスを完全に削除し、その中のivarプロパティを静的変数に置き換えることができます。実装。 TextureManager.m

これは、プロパティや設定を CoreData に保存しておらず、構成にのみ必要な場合に役立ちます。

この場合、静的変数のすべてのゲッターとセッターを作成する必要があり、クラスメソッドを使用してのみアクセスできることを覚えておいてください(ただし、それが要点です)。

その他の興味深いもの

この回答は、「イニシャライザ」メソッドをいつどのように呼び出すか、またはシングルトンを作成するかという問題に対する興味深い解決策を提供します。これを各シナリオで使用して、最初のシナリオでシングルトンを初期化するか、2 番目のシナリオでデフォルトをクラスレベルの静的にプリロードすることができます。

実装で静的シングルトンに固執したい場合は、この記事を参照して、シングルトンの真の「グローバルスコープ」をよりよく理解してください。

于 2014-01-23T05:25:07.070 に答える
2

はい、シングルトンを必要とせずに Texture クラスを確実に作成できます。

おそらく、シングルトンを作成してオブジェクトとして使用するべきではありません。

シングルトンは、多くの重要なことに使用できます。
確かに、それらが使用できるすべてのことを知っているわけではありませんが、過去にそれらを使用したことをお話しします.

私は通常、多くのレベルを持つゲーム (Angry Birds など) のレベル ナビゲーションにシングルトンを使用します。
レベル ナビゲーションとは、プレイヤーがゲームで特定のレベルを完了すると、シングルトンのクラス メソッドを呼び出してレベル番号を渡すだけで、シングルトンのクラス メソッドが次のレベルを判断します (ユーザーが「次のレベル」ボタン)。

于 2013-09-14T06:27:46.813 に答える