3

まず第一に、記事でこれを読みました-これは基本的に、シングルトンをまったく使用すべきではないことを示しています-

ほとんどの場合、シングルトンはインスタンスの作成時にパラメーターを指定することを許可しません。そうしないと、インスタンスの 2 番目の要求が別のパラメーターで行われると問題が発生する可能性があります。(同じパラメーターを持つすべてのリクエストに対して同じインスタンスにアクセスする必要がある場合は、ファクトリ パターンの方が適切です。)

パラメータと同じパラメータを持つ同じインスタンスが必要なので、ファクトリ パターンが必要であると結論付けました。

しかし、良いファクトリ パターンの実装をどこにも見つけることができませんでした。

パラメーターを使用した適切な c# シングルトン ファクトリ パターンの実装が見つかった場合は、親切に教えてください。

わかりました、ここで非常に具体的にしようと思います...これが私の状況を説明することを願っています.

代替方法は大歓迎です。多くの実装を組み合わせただけです - 私の理解は外れているかもしれません。

だから私はクラス'A'を持っています。データベースに接続するために使用されるクラスです - データベース接続。

接続には 4 つのパラメーターが必要で、制約は次のとおりです。

  1. 複数の接続を可能にする必要があります-異なるデータベースで(パラメーターが異なります)

  2. 特定の接続のインスタンスが1つだけ必要です-同じパラメーターを持つシングルトン(私の理解では)

  3. 上記の記事に従って、工場モデルが必要であり、接続数を制限したり、タイムアウト後に接続を閉じたりすることもできます。

これに基づいて、パラメータ/引数を持つシングルトンファクトリが必要です...私は仮定します

クラスAは次のようになります

<which access modifier ?> Class A {
    private Class A(string hostname, string port, string username, string pw_hash) {
        //create a new instance with the specified parameters
    }
    //other methods on the connection
    protected void close() {
        //close the connection
    }
}

public class AFactory//should it inherit class A?? {

        private IList<A> connections = new List<A>();
        private AFactory()
        {
            //do something
        }
        private static readonly Lazy<AFactory> lazy
            = new Lazy<AFactory>(() => new AFactory());

        public static AFactory Instance { get { return lazy.Value; } }

        public A getA(string hostname, string service, string username, string pw_hash)
        {
            foreach (A a in A)
            {
                if (a.hostname == hostname && a.service == service && a.username == username)
                    return a;
            }
            A d = new A(hostname, service, username, pw_hash);
            connections.Add(d);
            return d;
        }

これは、クラス A のコンストラクターがパブリックである限り、うまく機能しますが、シングルトンの目的に反します。このコードを機能させるにはどうすればよいですか。

指定されたパラメータに対してクラス A のインスタンスが 1 つだけ必要です。

ありがとう

インドラジット

4

4 に答える 4

2

ファクトリは、オブジェクトを管理するのではなく、オブジェクトを生成するために使用されます。あなたの状況にはDB接続マネージャーの方が適していると思います。マネージャーをシングルトンとして宣言できます。個々の接続には、内部クラス/構造体を使用できます。

以下の例を参照してください。

class DBConnectionManager
{        
    struct Connection
    {
      public string Hostname;
      public string ServerName;
      public string UserName;
      public string Password;

      public void Connect()
      {
      }

      public void Close()
      {
      } 
    }

    private static s_instance;
    public static DBConnectionManager Instance
    {
        get {return s_instance; }
    }

    private List<Connection> m_connections;

    public Connection GetConnection(string hostname, string serverName, string userName, string password)
    {
        // if already exist in m_connections
        // return the connection
        // otherwise create new connection and add to m_connections    
    }

    public void CloseConnection(string hostname, string serverName, string userName, string password)
    {
        // if find it in m_connections
        // then call Close()
    }

    public void CloseAll()
    {
        //
    }        
} 
于 2013-06-17T12:03:20.820 に答える
0

だから私はこれを行い、それはうまくいきます...それが正しいかどうか教えてください。また、スレッドセーフですか?

public Class A 
{
    private A(string hostname, string port, string username, string pw_hash) {
        //create a new instance with the specified parameters
    }
    //other methods on the connection
    protected void close() {
        //close the connection
    }
    public class AFactory 
    {
    private IList<A> connections = new List<A>();
    private AFactory()
    {
        //do something
    }
    private static readonly Lazy<AFactory> lazy
        = new Lazy<AFactory>(() => new AFactory());

    public static AFactory Instance { get { return lazy.Value; } }

    public A getA(string hostname, string service, string username, string pw_hash)
    {
        foreach (A a in connections)
        {
            if (a.hostname == hostname && a.service == service && a.username == username)
                return a;
        }
        A d = new A(hostname, service, username, pw_hash);
        connections.Add(d);
        return d;
    }
    }

}

私はこのように使用しています:

A.AFactory fact = A.AFactory.Instance;
A conn = fact.getA(a, b, c, d);
A conn2 = fact.getA(e, f, g, h);

この実装に明らかな問題がありますか?

于 2013-06-17T08:04:59.420 に答える
0

あなたはこれを試すことができます:

public static class Singlett<Param,T>
   where T : class
{
    static volatile Lazy<Func<Param, T>> _instance;
    static object _lock = new object();

    static Singlett()
    {
    }

    public static Func<Param, T> Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new Lazy<Func<Param, T>>(() =>
                {
                    lock (Singlett<Param,T>._lock)
                    {
                        try
                        {
                            ConstructorInfo constructor = null;
                            Type[] methodArgs = { typeof(Param) };                                
                            constructor = typeof(T).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, methodArgs, null);// Binding flags excludes public constructors.
                            if (constructor == null)
                            {
                                constructor = typeof(T).GetConstructor(BindingFlags.Public, null, methodArgs, null);
                                if (constructor == null)
                                    return delegate(Param o) { return (T)Activator.CreateInstance(typeof(T), new object[] { o }); };
                            }
                            return delegate(Param o) { return (T)constructor.Invoke(new object[] { o }); };
                        }
                        catch (Exception exception)
                        {
                            throw exception;
                        }
                    }
                });
            }
            return _instance.Value;
        }
    }
}

それを使用するには:代わりに

int i = 10;
MyClass class = new MyClass(i);

あなたは書ける:

int i = 10;
MyClass class = Singlett<int,MyClass>.Instance(i);
于 2014-01-10T01:12:41.023 に答える
-1

これを試して:

このインターフェイスは、ファクトリ初期化子から公開され、公開されたメソッドとプロパティが含まれています。

public interface IDatabase
{
    string ConnectionString { get; set; }
    IDataReader ExecuteSql(string sql);
}

さまざまなタイプのデータベース ファクトリに共通の機能を実行できるファクトリ基本抽象クラス。

public abstract class FactoryBase
{
    public FactoryBase() { }

    public abstract IDatabase GetDataLayer();
}

呼び出しを含む具体的な SQL クラス。ExecuteSql メソッドを見てください。接続はコマンドに含まれているため、開いたり閉じたり、破棄したりする必要はありません。

public class SQL : IDatabase
{
    private string m_ConnectionString = string.Empty;

    public string ConnectionString
    {
        get { return m_ConnectionString; }
        set { m_ConnectionString = value; }
    }

    public IDataReader ExecuteSql(string sql)
    {
        using (var command = new SqlCommand(sql, new SqlConnection(ConnectionString)) { CommandType = CommandType.Text, CommandText = sql, CommandTimeout = 0 })
        {
            if (command.Connection.State != ConnectionState.Open) command.Connection.Open();
            return command.ExecuteReader();
        }
    }
}

Sql 具象クラスのインスタンスを作成する Sql ファクトリ クラス。

class SQLFactory : FactoryBase
{
    public override IDatabase GetDataLayer()
    {
        return new SQL();
    }
}

開発者がファクトリの型を渡すために使用するファクトリ初期化クラスで、IDatabase を返します。

public static class FactoryInitializer
{
    public static IDatabase LoadFactory<T>(string connectionstring) where T : FactoryBase, new()
    {
        var factory = new T();
        var data = factory.GetDataLayer();
        data.ConnectionString = connectionstring;
        return data;
    }
}

次に、次のように使用します。

var factory = FactoryInitializer.LoadFactory<SQLFactory>(connectionString);
factory.ExecuteSql("SELECT ...");

その後、OracleFactory と Oracle 具象クラスを作成して、同じ方法で使用できます。

于 2013-06-17T07:52:15.413 に答える