如何初始化一个单例模式?

3
有时我们需要用一些辅助值初始化单例类。但是我们不能为其“发布”构造函数。有什么解决方法?
注意!我的想法并不包括重载GetInstance或设置颜色。颜色应该只设置一次。我希望确保MyPainter仅使用初始化的颜色进行绘制。任何默认颜色都不应该被使用。
为了更清晰起见,我提供一个示例:
''' <summary>
''' Singleton class MyPainter
''' </summary>
Public Class MyPainter
  Private Shared _pen As Pen
  Private Shared _instance As MyPainter = Nothing

  Private Sub New()
  End Sub

  ''' <summary>
  ''' This method should be called only once, like a constructor!
  ''' </summary>
  Public Shared Sub InitializeMyPainter(ByVal defaultPenColor As Color)
    _pen = New Pen(defaultPenColor)
  End Sub


  Public Shared Function GetInstance() As MyPainter
    If _instance Is Nothing Then
      _instance = New MyPainter
    End If

    Return _instance
  End Function

  Public Sub DrawLine(ByVal g As Graphics, ByVal pointA As Point, ByVal pointB As Point)
    g.DrawLine(_pen, pointA, pointB)
  End Sub

End Class

谢谢。
6个回答

3
如果您只想在创建时初始化一次,为什么不在构造函数内调用某个方法来获取参数进行初始化?如果需要多次调用此初始化操作,请将其转换为单独的方法,例如setOptions。

很遗憾,MyPainter不知道从哪里获取这些参数... 默认颜色应该明确定义。 - serhio

2

你不能只是重载你的GetInstance方法吗?


Dim _IsInitialized as boolean = false    
Public Shared ReadOnly Property IsInitialized() As Boolean
        Get
            Return _IsInitialized
        End Get
    End Property


Public Shared Function GetInstance() As MyPainter
        If _instance Is Nothing Then
            _instance = New MyPainter
        End If

        _IsInitialized = True
        Return _instance
    End Function

    Public Overloads Shared Function GetInstance(ByVal DefaultPenColor As Color) As MyPainter
        If _instance Is Nothing Then
            _instance = New MyPainter
            InitializeMyPainter(DefaultPenColor)
        End If

        _IsInitialized = True
        Return _instance
    End Function

在调用GetInstance方法之前,请检查它是否已经初始化。如果没有,请给它一个笔颜色。
If MyPainter.IsInitialized then
     Dim Painter as MyPainter = MyPainter.GetInstance
Else
     Dim Painter as MyPainter - MyPainter.GetInstance(System.Drawing.Color.Red)
EndIf

不,不,重载GetInstance并不是我的好主意。我想确保MyPainter仅使用初始化的颜色进行绘制。任何默认颜色都不应该被使用。 - serhio
我重载的 GetInstance 方法只会在第一次调用时设置画笔颜色。您可以添加一个额外的共享成员来查看类是否已初始化。我已更新代码示例。如果它仍然不符合您的需求,请告诉我。 - brad.huffman
我同意。然而,你的函数没有非常透明的公共意义,可能会误导(新的)开发者...其次,只有我这个单例创建者会知道并记得在使用之前不要忘记设置颜色。在无参数的GetInstance中_IsInitialized = True是不正确的,因为我不知道颜色是否已经初始化。 - serhio

1

你可以声明共享构造函数,但它们必须是无参数的:

Public Class MyPainter
    Private Shared _pen As Pen

    Shared Sub New()
        _pen = New Pen(Color.White)
    End Sub

    ....

End Class

你可以在构造函数中将颜色设置为合理的默认值,然后添加一个帮助方法来更改颜色(如果需要),就像你在示例中所做的那样:

Public Shared Sub SetColor(ByVal defaultPenColor As Color)
    _pen = New Pen(defaultPenColor)
End Sub

1

你可以在GetInstance中使用可选参数

Public Shared Function GetInstance(Optional ByVal defaultPenColor As Color = Colors.Red) As MyPainter
    If _instance Is Nothing Then
      If defaultPenColor is nothing then
          defaultPenColor = Colors.Red
      end if
      _pen = New Pen(defaultPenColor)
      _instance = New MyPainter
    End If

    Return _instance
End Function

所以,取决于第一次调用GetInstance()是带参数还是不带参数的,接下来的调用会得到不同的对象? 只有当您始终可以确定谁首先调用GetInstance()时,此方法才有效。 - Mattias Nilsson
不,它们将得到相同的对象。毕竟它是一个单例类。唯一改变的是初始笔颜色。 - Geoff Appleford
没错,那就是我想说的。今天我似乎无法用语言表达我的想法...但如果你无法控制第一次调用,那确实是个问题。 - Mattias Nilsson
无论你选择什么解决方案来解决这个问题,你都需要控制第一次调用,如果你想要使用一些参数进行初始化。至少这样,GetInstance总是返回一个有效的对象。如果你愿意,很容易添加一个公共方法以后更改值。 - Geoff Appleford
这很好,但我从来不确定是否有人想使用带参数的方法。因此,如果我们发现作为参数的Color(值类型)是引用类型,我从来不确定该成员是否为Nothing(null)。 - serhio
@serhio - 我不明白你的意思。无论是否提供参数,实例始终在第一次调用时初始化。我已更新代码,增加了一个额外的检查,以查看某人是否特别传递了空参数。 - Geoff Appleford

0
你可以使用一个初始化方法:(这是一个C#的例子,我刚好遇到了可初始化单例的同样问题)
public sealed class XSingleton
{
    private static XSingleton instance = null;
    int value = -1;

    private XSingleton(int v)
    {
        value = v;
    }

    public static void Init(int v)
    {
        if (instance != null) throw new Exception("Init() must be called only once!");
        instance = new XSingleton(v);
    }

    public static XSingleton Instance
    {
        get
        {
            if (instance == null) throw new Exception("Call Init() before!");
            return instance;
        }
    }

    public int Value { get { return value; } }
}

如果您尝试使用未初始化的XSingleton或尝试多次初始化,则会引发异常。
因此,您可以使用以下方式初始化单例:
XSingleton.Init(123);

现在您可以使用初始化的值:

Console.WriteLine(XSingleton.Instance.Value);

0
创建一个带有必需参数的CreateInstance方法,并从GetInstance中删除创建能力。虽然不是完全的单例模式,但至少您知道事情将被正确初始化。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接