哪种方法适合辛格尔顿

本文关键字:方法 | 更新日期: 2023-09-27 17:59:50

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

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

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

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

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

那么,你有什么建议?

哪种方法适合辛格尔顿

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

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

略有不同,这可能会使参数不是强制性的,如果你需要的话,使用命名参数,比如:

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

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

我会:

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

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

  • 一个静态方法Config ParseCommandLine(),它获取实际的命令行并调用上面的方法(有点难看,因为它访问全局可变状态)
  • 最后使用Config.SetInstance(ParseCommandLine())来支持"singleton"上的Instance属性。这有点难看,但使用singleton一开始就很难看

这个"singleton"并没有真正强制要求有一个配置,但它更像是一个默认实例。根据我的经验,很少需要真正的单身汉,甚至默认实例也有点像黑客。

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

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属性,将配置注入到需要它的对象中。但对于一个可能过于工程化的小程序来说。

在您的情况下,最好不要使用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;
    }
}