静的クラスとシングルトン パターンの間に存在する実際の (つまり実用的な) 違いは何ですか?
どちらもインスタンス化せずに呼び出すことができ、どちらも「インスタンス」を 1 つしか提供せず、どちらもスレッドセーフではありません。他に違いはありますか?
静的クラスとシングルトン パターンの間に存在する実際の (つまり実用的な) 違いは何ですか?
どちらもインスタンス化せずに呼び出すことができ、どちらも「インスタンス」を 1 つしか提供せず、どちらもスレッドセーフではありません。他に違いはありますか?
シングルトンまたは静的メソッドのいずれかがスレッドセーフでないと言う理由は何ですか? 通常、どちらもスレッドセーフになるように実装する必要があります。
シングルトンと一連の静的メソッドの大きな違いは、シングルトンはインターフェイスを実装できる (または、私の経験ではあまり一般的ではありませんが、有用な基本クラスから派生する) ことができるため、シングルトンを「単なる別のメソッド」であるかのように渡すことができることです。 " 実装。
本当の答えは、別のフォーラムの Jon Skeet によるものです。
シングルトンは、作成された単一のインスタンスへのアクセスを許可します。そのインスタンス (またはそのインスタンスへの参照) は、パラメーターとして他のメソッドに渡され、通常のオブジェクトとして扱われます。
静的クラスでは、静的メソッドのみが許可されます。
interface
が、クラスの静的メソッド (または C#static class
など) では実装できません。Singleton パターンには、静的クラスよりもいくつかの利点があります。まず、シングルトンはクラスを拡張してインターフェイスを実装できますが、静的クラスはできません (クラスを拡張できますが、インスタンス メンバーを継承しません)。シングルトンは遅延または非同期で初期化できますが、静的クラスは通常、最初にロードされたときに初期化されるため、クラスローダーの問題が発生する可能性があります。ただし、最も重要な利点は、ユーザーにインスタンスが 1 つだけであると想定させることなく、シングルトンをポリモーフィックに処理できることです。
static
クラスは、状態を必要とするものではありません。Math
たくさんの関数をまとめる、つまり(またはUtils
プロジェクトに)入れるのに便利です。したがって、クラス名は、関数を見つけることができる場所の手がかりを提供するだけで、それ以上のものはありません。
Singleton
は私のお気に入りのパターンで、何かを 1 点で管理するために使用します。static
クラスよりも柔軟で、状態を維持できます。インターフェイスを実装し、他のクラスから継承し、継承を許可できます。
static
と の間で選択するための私のルールsingleton
:
一緒に保持する必要がある関数がたくさんある場合は、それstatic
が選択です。一部のリソースへの単一アクセスが必要なその他のものは、 として実装できますsingleton
。
静的クラス:-
static クラスのインスタンスは作成できません。
クラスを含むプログラムまたは名前空間が読み込まれるときに、.NET Framework 共通言語ランタイム (CLR) によって自動的に読み込まれます。
静的クラスをメソッドに渡すことはできません。
C# では Static クラスを別の Static クラスに継承することはできません。
すべての静的メソッドを持つクラス。
パフォーマンスの向上 (静的メソッドはコンパイル時に結合されます)
シングルトン:-
オブジェクトのインスタンスを 1 つ作成して再利用できます。
シングルトン インスタンスは、ユーザーが要求したときに初めて作成されます。
シングルトンクラスのオブジェクトを作成してメソッドに渡すことができます。
シングルトンクラスには継承の制限はありません。
シングルトン クラスのオブジェクトは破棄できますが、静的クラスのオブジェクトは破棄できません。
メソッドはオーバーライドできます。
必要に応じて遅延ロードできます (静的クラスは常にロードされます)。
インターフェイスを実装できます(静的クラスはインターフェイスを実装できません)。
静的クラスは、静的メソッドのみを持つクラスであり、より適切な言葉は「関数」です。静的クラスで具現化された設計スタイルは、純粋に手続き型です。
一方、シングルトンは OO 設計に固有のパターンです。これはオブジェクトのインスタンスであり (ポリモーフィズムなど、オブジェクトに固有のすべての可能性を備えています)、その特定のロールのインスタンスがそのライフタイム全体にわたって 1 つだけ存在することを保証する作成手順を備えています。
シングルトン パターンでは、派生型のインスタンスとしてシングルトンを作成できますが、静的クラスでは作成できません。
簡単な例:
if( useD3D )
IRenderer::instance = new D3DRenderer
else
IRenderer::instance = new OpenGLRenderer
Jon Skeet's Answerを拡張するには
シングルトンと一連の静的メソッドの大きな違いは、シングルトンはインターフェースを実装できる (または有用な基本クラスから派生しますが、IME はあまり一般的ではありません) ため、シングルトンを「単なる別の」実装であるかのように渡すことができることです。
クラスを単体テストするときは、シングルトンを使用する方が簡単です。シングルトンをパラメーター (コンストラクター、セッター、またはメソッド) として渡す場合はいつでも、代わりにシングルトンのモックまたはスタブ バージョンを置き換えることができます。
良い記事は次のとおりです 。
メソッドをオーバーライドすることはできませんが、メソッドの隠蔽を使用できます。( Java のメソッド隠蔽とは? JavaDoc の説明でさえわかりにくい)
public class Animal {
public static void foo() {
System.out.println("Animal");
}
}
public class Cat extends Animal {
public static void foo() { // hides Animal.foo()
System.out.println("Cat");
}
}
要約すると、util メソッドを保持するためにのみ静的クラスを使用し、それ以外はすべて Singleton を使用します。
編集
静的クラスも遅延ロードされます。ありがとう@jmoreno(静的クラスの初期化はいつ行われますか?)
静的クラスのメソッド隠蔽。ありがとう@MaxPeng。
シングルトンのもう 1 つの利点は、簡単にシリアル化できることです。これは、その状態をディスクに保存する必要がある場合や、リモートのどこかに送信する必要がある場合に必要になる場合があります。
私は優れた OO 理論家ではありませんが、私の知る限り、シングルトンと比較して静的クラスに欠けている唯一の OO 機能はポリモーフィズムだと思います。しかし、それが必要ない場合は、静的クラスを使用して、もちろん継承 (インターフェイスの実装については不明) とデータと関数のカプセル化を行うことができます。
モレンディルのコメント、「静的クラスで具現化された設計スタイルは純粋に手続き型です」私は間違っているかもしれませんが、私は同意しません。静的メソッドでは、静的メンバーにアクセスできます。これは、単一インスタンス メンバーにアクセスするシングルトン メソッドとまったく同じです。
編集:
私は実際に、別の違いは、静的クラスがプログラムの開始時にインスタンス化され*、プログラムの存続期間全体にわたって存続することであると考えていますが、シングルトンはある時点で明示的にインスタンス化され、破棄される可能性もあります。
* または、言語によっては、最初の使用時にインスタンス化される場合があると思います。
Jon の要点を説明するために、Logger が静的クラスである場合、以下に示されていることは実行できません。クラスは、実装SomeClass
のインスタンスがILogger
そのコンストラクターに渡されることを期待しています。
依存性注入を可能にするためには、シングルトン クラスが重要です。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
var someClass = new SomeClass(Logger.GetLogger());
}
}
public class SomeClass
{
public SomeClass(ILogger MyLogger)
{
}
}
public class Logger : ILogger
{
private static Logger _logger;
private Logger() { }
public static Logger GetLogger()
{
if (_logger==null)
{
_logger = new Logger();
}
return _logger;
}
public void Log()
{
}
}
public interface ILogger
{
void Log();
}
}
シングルトンはインスタンス化された通常のクラスですが、クライアントコードから間接的に一度だけです。静的クラスはインスタンス化されていません。私の知る限り、静的メソッド (静的クラスには静的メソッドが必要です) は、非静的よりも高速です。
編集:
FxCop パフォーマンス ルールの説明: 「インスタンス データにアクセスしたり、インスタンス メソッドを呼び出したりしないメソッドは、静的 (VB で共有) としてマークできます。その後、コンパイラは非仮想呼び出しサイトをこれらのメンバーに発行します。現在のオブジェクト ポインタが null でないことを保証する各呼び出しを実行時にチェックします。これにより、パフォーマンスが重要なコードのパフォーマンスが大幅に向上する可能性があります。場合によっては、現在のオブジェクト インスタンスへのアクセスの失敗が正確性の問題を表しています。
これが静的クラスの静的メソッドにも当てはまるかどうかは実際にはわかりません。
シングルトンはインスタンス化されています。インスタンス化されたインスタンスは 1 つしかないため、シングルトンのシングルです。
静的クラスは、それ自体以外ではインスタンス化できません。
JDKにはシングルトンと静的の両方の例があり、一方java.lang.Math
では静的メソッドを持つ最終クラスであり、他方java.lang.Runtime
ではシングルトンクラスです。
シングルトンの利点
シングルトン パターンよりも状態を維持する必要がある場合は、静的クラスよりも適切な選択です。静的クラスで状態を維持すると、特に同時実行環境でバグが発生し、複数のスレッドによる適切な同期並列変更なしで競合状態が発生する可能性があるためです。
シングルトン クラスは重いオブジェクトであれば遅延ロードできますが、静的クラスにはそのような利点がなく、常に熱心にロードされます。
シングルトンでは、継承とポリモーフィズムを使用して基本クラスを拡張し、インターフェイスを実装し、さまざまな実装を提供できます。
Java の静的メソッドはオーバーライドできないため、柔軟性がなくなります。一方、singleton クラスで定義されているメソッドは、継承することでオーバーライドできます。
静的クラスの欠点
静的クラスの利点
それぞれの詳細な説明は冗長すぎるため、良い記事へのリンクを貼っておきます -シングルトンについて知りたいことすべて
シングルトンは、テストの観点から優れたアプローチです。静的クラスとは異なり、シングルトンはインターフェースを実装でき、モックインスタンスを使用してそれらを注入できます。
以下の例で、これを説明します。メソッド getPrice() を使用するメソッド isGoodPrice() があり、シングルトンのメソッドとして getPrice() を実装するとします。
getPrice 機能を提供するシングルトン:
public class SupportedVersionSingelton {
private static ICalculator instance = null;
private SupportedVersionSingelton(){
}
public static ICalculator getInstance(){
if(instance == null){
instance = new SupportedVersionSingelton();
}
return instance;
}
@Override
public int getPrice() {
// calculate price logic here
return 0;
}
}
getPrice の使用:
public class Advisor {
public boolean isGoodDeal(){
boolean isGoodDeal = false;
ICalculator supportedVersion = SupportedVersionSingelton.getInstance();
int price = supportedVersion.getPrice();
// logic to determine if price is a good deal.
if(price < 5){
isGoodDeal = true;
}
return isGoodDeal;
}
}
In case you would like to test the method isGoodPrice , with mocking the getPrice() method you could do it by:
Make your singleton implement an interface and inject it.
public interface ICalculator {
int getPrice();
}
最終的なシングルトンの実装:
public class SupportedVersionSingelton implements ICalculator {
private static ICalculator instance = null;
private SupportedVersionSingelton(){
}
public static ICalculator getInstance(){
if(instance == null){
instance = new SupportedVersionSingelton();
}
return instance;
}
@Override
public int getPrice() {
return 0;
}
// for testing purpose
public static void setInstance(ICalculator mockObject){
if(instance != null ){
instance = mockObject;
}
テストクラス:
public class TestCalculation {
class SupportedVersionDouble implements ICalculator{
@Override
public int getPrice() {
return 1;
}
}
@Before
public void setUp() throws Exception {
ICalculator supportedVersionDouble = new SupportedVersionDouble();
SupportedVersionSingelton.setInstance(supportedVersionDouble);
}
@Test
public void test() {
Advisor advidor = new Advisor();
boolean isGoodDeal = advidor.isGoodDeal();
Assert.assertEquals(isGoodDeal, true);
}
}
getPrice() の実装に静的メソッドを使用するという代替手段を取る場合、getPrice() をモックするのは困難でした。power mock で static をモックできますが、すべての製品がそれを使用できるわけではありません。
私はこの定義に同意します:
「単一」という言葉は、アプリケーションのライフ サイクル全体で単一のオブジェクトを意味するため、スコープはアプリケーション レベルになります。
staticにはオブジェクト ポインターがないため、スコープはアプリ ドメイン レベルになります。
さらに、どちらもスレッドセーフになるように実装する必要があります。
以下について、興味深い他の違いを見つけることができます:シングルトン パターンと静的クラス
注目すべき違いの 1 つは、シングルトンに付属する異なるインスタンス化です。
静的クラスでは、CLR によって作成され、制御できません。シングルトンでは、オブジェクトは、アクセスが試みられた最初のインスタンスでインスタンス化されます。
多くの場合、特にシングルトン インスタンスがまったく変更されないか、構成を保持するなど非常にゆっくりと変更される場合、これら 2 つに実質的な違いはありません。
最大の違いは、特殊な静的のみの Java クラスとは対照的に、シングルトンがまだ通常の Java Bean であることです。このため、シングルトンはより多くの状況で受け入れられます。実際、これはデフォルトの Spring Framework のインスタンス化戦略です。コンシューマは、それが渡されたシングルトンであることを認識している場合と認識していない場合があります。コンシューマは、それを通常の Java Bean のように扱います。要件が変更され、代わりにシングルトンがプロトタイプになる必要がある場合、Spring でよく見られるように、消費者へのコード行の変更なしで完全にシームレスに実行できます。
他の誰かが以前に、静的クラスは純粋に手続き型であるべきだと述べました。例えば、java.lang.Math. 私の考えでは、そのようなクラスは決して渡されるべきではなく、 static final 以外のものを属性として保持するべきではありません。それ以外の場合は、はるかに柔軟で保守が容易なシングルトンを使用してください。
バックエンドに接続する DB フレームワークがあります。複数のユーザー間でのダーティ リードを回避するために、シングルトン パターンを使用して、いつでも単一のインスタンスを利用できるようにしました。
C# では、静的クラスはインターフェイスを実装できません。単一のインスタンス クラスがビジネス コントラクトまたは IoC の目的でインターフェイスを実装する必要がある場合、ここで静的クラスを使用せずにシングルトン パターンを使用します。
シングルトンは、ステートレス シナリオで状態を維持する方法を提供します
それがあなたを助けることを願っています..
私は以下を読んで、それも理にかなっていると思います:
ビジネスの世話をして
最も重要な OO ルールの 1 つは、オブジェクトがそれ自体に責任を持つということです。つまり、クラスのライフサイクルに関する問題は、静的などの言語構造に委譲するのではなく、クラスで処理する必要があります。
本オブジェクト指向思考プロセス第4版から。
a. シリアル化 - 静的メンバーはクラスに属しているため、シリアル化できません。
b. コンストラクターをプライベートにしましたが、静的メンバー変数はサブクラスに引き継がれます。
c. クラスのロード時にのみすべてがロードされるため、遅延初期化を行うことはできません。
クライアントの観点からは、静的な動作はクライアントに知られていますが、シングルトンの動作はクライアントから隠されている可能性があります。クライアントは、何度も何度も遊んでいるインスタンスが 1 つしかないことを決して知らないかもしれません。
単一の静的クラスインスタンス (つまり、たまたま静的変数またはグローバル変数であるクラスの単一インスタンス) と、ヒープ上のクラスのインスタンスへの単一の静的ポインターとの間には大きな違いがあります。
アプリケーションが終了すると、静的クラス インスタンスのデストラクタが呼び出されます。つまり、その静的インスタンスをシングルトンとして使用すると、シングルトンが正しく機能しなくなります。たとえば別のスレッドで、そのシングルトンを使用するコードがまだ実行されている場合、そのコードはクラッシュする可能性があります。
完全な機能を備えたクラスが必要な場合、たとえば、多くのメソッドと変数がある場合は、シングルトンを使用します。
SendMail() メソッドが 1 つしかない MailService クラスなど、メソッドが 1 つまたは 2 つしかないクラスが必要な場合は、静的クラスとメソッドを使用します。
シングルトンの主な利点の 1 つ: ポリモーフィズム 例: クラス ファクトリを使用してインスタンスを作成し (構成に基づいて言う)、このオブジェクトを本当にシングルトンにしたい。
どちらもインスタンス化せずに呼び出すことができ、どちらも「インスタンス」を 1 つしか提供せず、どちらもスレッドセーフではありません。他に違いはありますか?
質問は間違っています。両方のステートメントです。注意: ここでの静的クラスは、ネストされた静的クラスを意味し、静的メソッドのみを持つクラスではありません。
私は仮定しています(つまり、静的クラスはネストされた静的クラスを意味し、静的メンバーのみを持つクラスではありません)、最も人気のあるSingleton実装、つまりDCLの方法を見ると、インスタンスの静的宣言とSingletonインスタンスを取得するための静的メソッドにすぎないためです。その1つの実装。したがって、この場合、シングルトンと静的メンバーのみを持つクラスの違いは何ですか。Enumを使用すると、他の実装も可能です。
ステートメントを修正させてください。
シングルトン クラスは、アプリケーション全体で単一のインスタンスを持つことができます。ネストされた静的クラスは複数のインスタンスを持つことができます (証明として以下のコードを参照してください)。ネストされたクラスの基本については、こちらをご覧ください。
本質的にスレッドセーフなクラスはなく、プログラムでスレッドセーフにする必要があります。ネストされた静的クラスとシングルトンの両方で実行できます。
いくつかの神話バスターを以下に示します(この質問への回答のほとんどはこれらのステートメントを提供しているため、プログラムで証明するのが良いと思いました):
以下のコードでは、ネストされた静的クラスNestedStaticClassがインターフェイスを実装し、別のクラスを拡張し、インスタンス変数とパラメーター化されたコンストラクターを持っていることがわかります。
package com.demo.core;
public class NestedStaticClassTest
{
public static void main(String[] args)
{
OuterClass.NestedStaticClass obj1 = new OuterClass.NestedStaticClass();
OuterClass.NestedStaticClass obj2 = new OuterClass.NestedStaticClass();
if(obj1 == obj2)
{
System.out.println("Both nested static objects are equal....");
}
else
{
System.out.println("NOT EQUAL......");
}
System.out.println(OuterClass.NestedStaticClass.d);
obj1.setD(5);
System.out.println(OuterClass.NestedStaticClass.d);
System.out.println(obj1.sum());
}
}
class OuterClass
{
int a =1;
static int b = 2;
static class NestedStaticClass extends OneClass implements Sample
{
int c = 3;
static int d = 4;
public NestedStaticClass()
{
}
//Parameterized constructor
public NestedStaticClass(int z)
{
c = z;
}
public int sum()
{
int sum = 0;
sum = b + c + d + getE();
return sum;
}
public static int staticSum()
{
int sum = 0;
sum = b + d;
return sum;
}
public int getC()
{
return c;
}
public void setC(int c)
{
this.c = c;
}
public static int getD()
{
return d;
}
public static void setD(int d)
{
NestedStaticClass.d = d;
}
}
}
interface Sample
{
}
class OneClass
{
int e = 10;
static int f = 11;
public int getE()
{
return e;
}
public void setE(int e)
{
this.e = e;
}
public static int getF()
{
return f;
}
public static void setF(int f)
{
OneClass.f = f;
}
}
WTMI と WTL;DR の応答を上回るようにします。
シングルトンはオブジェクトのインスタンスです...終止符
あなたの質問は、基本的に、クラスとそのクラスのインスタンスの違いについて尋ねています。それはかなり明確で、詳細な説明は必要ないと思います。
通常、シングルトンのクラスは、1 つのインスタンスを確実に構築するための手順を実行します。それはスマートですが、必須ではありません。
例: var connection = Connection.Instance;
これが Connection クラスだとします。
public sealed class Connection
{
static readonly Connection _instance = new Connection();
private Connection()
{
}
public static Connection Instance
{
get
{
return _instance;
}
}
}
そのクラスでインターフェイスをスローし、テスト目的でそれをモックできることに注意してください。これは、静的クラスでは簡単に行うことができません。