繁体   English   中英

单例对象的实例成员或类的静态成员

[英]Instance members of singleton object or static members of class

我正在编写一个侦听器类,该类在随机未使用的端口上创建一个HttpListener并在其上侦听。 我试图使其单身。 但是,我发现在侦听随机HTTP端口失败10次时,很难将该单例对象保持为null

(我已将端口号和HttpListener实例显示为单例实例的成员。但是,为简单起见,还有许多其他成员未显示。)这是我的代码:

class Listener
{
    private static Listener listener = null;  //singleton instance

    //member variables
    private HttpListener httpListener = null;
    private int port = -1;

    static Listener()
    {
        listener = new Listener();
    } 

    private Listener()
    {
        try
        {
            port = //randomly generate
            httpListener = new HttpListener();
            //start listening
        }   
        catch(Exception ex)
        {
            //cant listen on randomly chosen port
            listener = null;
        httpListener = null;
            port = -1;
            return;            
        }   
    }
}

但是,在catch()内部, listener = null会将listener设置为null一段时间。 当默认构造函数返回时,它将返回Listener的新实例,因此静态构造函数内部的listener始终会为其分配实例。 因此,代替默认构造函数中的listener = null它应该是this = null ,这是无效的。

因此,我将整个代码移到了静态构造函数中。 但这迫使我

  • 使实例成员( porthttpListenerstatic
  • 或在各处使用listener.portlistener.httpListener

    类Listener {private static Listener listener = null; //单个实例

     //member variables private HttpListener httpListener = null; private int port = -1; static Listener() { listener = new Listener(); try { listener.port = //randomly generate listener.httpListener = new HttpListener(); //start listening } catch(Exception ex) { //cant listen on randomly chosen port listener = null; return; } } private Listener() { } 

    }

我不明白

Q1是否使porthttpListener static (我觉得这有点违反OOP原则)或

Q2是否保留它们作为实例成员并使用listener. 到处? (这是有问题的,因为在我的实际代码中有很多这样的成员和方法,并且我必须在每个地方附加listener.

还是我认为这都是错误的,应该采取不同的方法?

直接的问题是,一旦失败,实例构造函数会将静态成员侦听器设置为null。 但是,控制权然后返回到静态构造函数,后者将静态成员侦听器设置为在实例构造函数中创建的对象。 因此,您所看到的行为。

我认为您的(实例)构造函数试图做太多事情。 我会将“开始侦听”逻辑移到单独的方法中,然后从实例构造函数以外的任何地方调用它。 这将使您的错误处理更加容易,例如

class Listener
{
    public static Listener listener = null;  //singleton instance

    //member variables
    private HttpListener httpListener = null;
    private int port = -1;

    static Listener GetListener()
    {
        if (listener != null)
        {
            return listener;
        }

        try
        {
            listener = new Listener();
            listener.StartListening();
            return listener;
        }
        catch (Exception)
        {
            //cant listen on randomly chosen port
            listener.Cleanup();
            listener = null;
            throw;
        }
    }

    private Listener()
    {
        port = RandomlyGenerate();
        httpListener = new HttpListener();
    }

    private void StartListening()
    {
        //start listening
    }

    private void Cleanup()
    {
        httpListener.Close();
        httpListener = null;
        port = -1;
    }
}

正如BartoszKP在评论中提到的那样,在此处使用工厂模式可能会更好。

如果您对事件有一个通用的位置感兴趣, 可以将该事件放置在factory类中,或者在Listener类中实现一个静态事件。

public class ListenerFactory {

    public IListener CreateListener(URI uri, int port) {
        Listener l = new Listener();
        l.MessageReceived += OnMessageReceived;
        // do whatever with l. loop until connection, or use l.Start() for instance
        return l;
    }

    public static event EventHandler<MessageEventArgs> ListenerMessageReceived;

    private static void OnMessageReceived(object sender, MessageEventArgs e) {
        // trigger ListenerMessageReceived
    }
}

public interface IListener {
    event EventHandler<MessageEventArgs> MessageReceived;
    void Send(byte[] data);
}

public class Listener : IListener {
    // implement interface
}

然后,您只需调用new ListenerFactory().Create(host, port); 当您需要新的侦听器时,并且如果您想侦听所有消息,则可以订阅ListenerFactory.MessageReceived接收传入消息。

使用此模式,您可以一次创建多个连接,而不必依赖一个类来处理所有连接。


您应该将httpListener的初始化代码移至其自己的方法,以避免重新创建侦听器。 通过这样做,并添加用于获取侦听器实例的属性,如果静态构造函数无法连接,则类可以使用Listener.Instance.Start()重新连接。

public class Listener
{
    private static Listener listener = null;  //singleton instance

    //member variables
    private HttpListener httpListener = null;
    private int port = -1;

    static Listener()
    {
        listener = new Listener();
        // start listener
        try {
             listener.Start();
         }
         catch { }
    }

    // Use this method in other classes to start listener if it fails
    // in static constructor
    public static Listener Instance { get { return listener; } }

    private Listener()
    {
    }

     public bool IsConnected {
         get { return httpListener != null; }
     }

     public void Start() 
     {
        if (IsConnected) { return; }
        try
        {
            port = //randomly generate
            httpListener = new HttpListener();
            //start listening
        }   
        catch(Exception ex)
        {
            //cant listen on randomly chosen port
        httpListener = null;
            port = -1;
            return;            
        }   
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM