Singleton的哪种方法更好?

时间:2013-02-17 16:45:03

标签: c# design-patterns singleton

我的程序使用命令行传递的参数实例化一个对象。我需要能够使用这些参数实例化一个对象但是它应该只创建一次。我已阅读这些帖子1& 2但我仍然不明白哪种方法更好:

1 - var myInstance = MyClass.Instance.Create("param1", "param2");

OR

2 - var myInstance = MyClass.Instance;
    myInstance.setParam1("param1");
    myInstance.setParam2("param2");

在第一种方法中,将创建传递给Create的每个不同参数对的新实例。防止这种情况的唯一方法是在Create内设置将返回已创建实例的标志。

在第二种方法中,问题是如果MyClass的构造函数依赖于param1param2

那么,你会建议什么?

3 个答案:

答案 0 :(得分:1)

您也可以使用第一种方法:

MyClass.Instance.Create("param1", "param2")

略有不同,如果需要,可以使参数,使用Named Parameters,例如:

MyClass.Instance.Create(param1 = "param1", param2 = "param2")

因此,您可以完全避免使用参数(在调用期间)并使用声明中提供的默认值。

答案 1 :(得分:0)

我最好:

  • 使用带有参数
  • 的公共构造函数创建一个不可变的Config
  • 创建一个静态方法Config ParseCommandLine(string),将命令行转换为Config对象。

    由于这是一个纯函数(没有副作用,没有全局状态),因此很容易测试它。

  • 一个静态方法Config ParseCommandLine(),它获取实际的命令行并调用上面的方法(有点难看,因为它访问全局可变状态)
  • 最后使用Config.SetInstance(ParseCommandLine())支持“单身人士”上的Instance属性。这有点难看,但首先使用单身人士是丑陋的。

这个“单例”并没有真正强制执行单个配置,但它更像是一个默认实例。根据我的经验,很少需要真正的单身人士,甚至默认的实例都是一种黑客攻击。

你最终会得到这样的东西:

public class Config
{
    public string Param1{get;private set;}
    public int Param2(get;private set;}

    public Config(string param1, int param2)
    {
        Param1=param1;
        Param2=param2;
    }

    // take a string[] if you prefer to use Environment.GetCommandLineArgs
    public Config ParseCommandLine(string commandLine)
    {
        string param1=...;
        int param2=...;

        return new Config(param1:param1, param2:param2);
    }

    public Config ParseCommandLine()
    {
       return ParseCommandLine(Environment.CommandLine);
    }
}

我还考虑抛弃静态Instance属性,支持将配置注入需要它的对象。但是对于一个可能过度工程的小程序。

答案 2 :(得分:0)

在你的情况下,最好不要使用单身人士。

Singleton的意图:

  • 确保只创建一个类的一个实例。
  • 提供对象的全局访问点。

http://www.oodesign.com/singleton-pattern.html

如果需要确保只允许一个实例,请使用私有静态属性作为标志。

更新

public class MyClass {

    private static boolean isAlreadyInitiated = false;

    public MyClass() {
        if(isAlreadyInitiated){
            throw new IllegalStateException("Only one instance allowed.");
        }
        isAlreadyInitiated = true;
    }
}