首先,我在一篇文章上读到了这篇文章 - 它基本上告诉我我根本不应该使用单例 -
最常见的是,单例不允许在创建实例时指定任何参数 - 否则使用不同参数对实例进行第二次请求可能会出现问题! (如果所有具有相同参数的请求都应该访问同一个实例,那么工厂模式更合适。)
因为我需要参数,以及具有相同参数的相同实例 - 我得出的结论是我需要一个工厂模式。
但是我无法在任何地方找到好的工厂模式实现。
如果您找到任何好的带参数的 C# 单例工厂模式实现,请指导我
好吧,我将尝试在这里非常具体......希望这可以解释我的情况。
欢迎使用替代方法。我只是结合了很多实现 - 我的理解可能不正确。
所以我有一节课'A'。它是一个用于连接数据库的类 - 数据库连接。
连接需要 4 个参数,约束条件是:
我需要有多个可能的连接 - 使用不同的数据库(参数不同)
我只需要特定连接的 1 个实例 - 参数相同的单例(以我的理解)
我需要一个工厂模型,按照上面提到的文章,还需要限制连接数,超时后关闭连接等。
在此基础上,我需要一个带有参数/参数的单例工厂......我认为
所以 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 类实例。
谢谢
因德拉吉特
工厂用于生成对象而不是管理对象。我认为数据库连接管理器更适合您的情况。您可以将管理器声明为单例。对于单独的连接,您可以使用内部类/结构。
见下面的例子:
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()
{
//
}
}
所以我已经这样做了并且它有效......你能告诉我它是否正确。它也是线程安全的吗?
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);
这个实现有什么明显的错误吗?
你可以试试这个:
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);
试试这个:
此接口从工厂初始值设定项公开,并包含公开的方法和属性。
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 具体类,并以相同的方式使用它。