3

首先,我在一篇文章中读到了这篇文章——它基本上告诉我我根本不应该使用单例——

最常见的是,单例不允许在创建实例时指定任何参数 - 否则对实例的第二次请求但使用不同的参数可能会出现问题!(如果所有具有相同参数的请求都应该访问相同的实例,则工厂模式更合适。)

因为我需要参数,以及具有相同参数的相同实例 - 我得出结论我需要一个工厂模式。

但是我无法在任何地方找到一个好的工厂模式实现。

如果您发现任何带有参数的良好 c# 单例工厂模式实现,请指导我

好的,我将尝试在这里非常具体......希望这能解释我的情况。

替代方法是最受欢迎的。我只是结合了很多实现-我的理解可能不正确。

所以我有一个班级'A'。它是一个用于连接数据库的类——数据库连接。

连接需要 4 个参数 & 约束是:

  1. 我需要有多个连接可能 - 使用不同的数据库(参数不同)

  2. 我只需要一个特定连接的实例 - 一个参数相同的单例(在我的理解中)

  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 构造函数是公共的,这就会很好地工作——但这​​有点违背了单例的目的。我需要做什么才能使此代码正常工作。

对于指定的参数,我只需要 1 个 A 类实例。

谢谢

英德拉吉特

4

4 回答 4

2

工厂用于生成对象而不是管理对象。我认为数据库连接管理器更适合您的情况。您可以将经理声明为单例。对于单个连接,您可以使用内部类/结构。

请参见下面的示例:

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 回答