9

我意识到有很多关于单例以及为什么不好的讨论。这不是这个问题的目的。我了解单身人士的缺点。

我有一个场景,使用单例很容易并且看起来很有意义。但是,我想要一个替代方案,它可以在没有大量开销的情况下完成我所需要的。

我们的应用程序设计为客户端,通常在现场的笔记本电脑上运行并与后端服务器通信。我们在主应用程序的底部有一个状态栏。它包含一些显示各种雕像和信息的文本区域以及几个图标。图标更改其图像以指示其状态。例如指示是否连接的 GPS 图标以及错误状态。

我们的主类称为 MobileMain。它拥有状态栏区域并负责创建它。然后我们有一个 StatusBarManager 类。StatusBarManager 目前是一个静态类,但也可以是一个单例。这是课程的开始。

public static class StatusBarManager
{
    static ScreenStatusBar StatusBar;

    /// <summary>
    /// Creates the status bar that it manages and returns it.
    /// </summary>
    public static ScreenStatusBar CreateStatusBar()
    {
        StatusBar = new ScreenStatusBar();
        return StatusBar;
    }

MobileMain 向 StatusBarManager 请求 StatusBar。然后它使用状态栏。没有其他类看到 StatusBar,只有 StatusBarManager。

状态栏的更新几乎可以来自应用程序中的任何地方。大约有 20 个类可以更新状态栏上的文本区域,还有其他类可以更新图标状态。

只有一个 StatusBar 和一个 StatusBarManager。

有什么更好的实施建议吗?

我的一些想法:

使 StatusBarManager 成为一个实例类。在我的 MobileMain 类中,保留 StatusBarManager 类的静态公共实例。然后要进行状态栏更新,您将调用 MobileMain.StatusBarManager.SetInformationText 或管理器的其他方法。StatusBarManager 不会是单例,但 MobileMain 只会创建它的静态实例。这里的问题是 MobileMain 现在有一个 StatusBar 和一个 StatusBarManager,它只管理它拥有的 StatusBar。仍然有一个全局可用的 StatusBarManager 静态实例,只是一个不同的所有者。

另一个想法是使用类似 EventEggregator 类的东西。我从来没有用过,但读过它们。我想这个概念是它将是一个全球可用的类。在每个想要更新状态栏的类中,它都会发布一个 StatusBarUpdate 事件。StatusBarManager 将是唯一订阅 StatusBarUpdate 事件的类,并接收所有通知。我已经阅读过,如果您在清理对象时不小心取消订阅事件,那么这种方法可能会导致泄漏。这种方法值得研究吗?

4

5 回答 5

3

我更喜欢包含您的对象的静态类。因此,您可以访问的对象数量取决于您的静态类提供的接口。只要您的应用程序仍然可以扩展,静态就不错。

单例的另一个很好的替代方案是 Monostate 模式,其中您有一个实现私有静态字段的类来表示“单例”行为。

参见:
Monostate
Monostate vs. Singleton

更新: 它经常帮助我牢记 REST 之类的 api,即使对于内部程序结构也是如此。在引发条件和无限循环(更新 -> 事件 -> 更新 -> ...)方面,很难控制一个从任何地方更新并向每个人发送通知的类

构建一个(静态或非静态)状态栏界面,您可以在需要的地方访问它。通过一个静态类,您可以访问您的状态栏界面,或者如果您使用此类技术,则通过依赖注入(不推荐用于较小的项目)。对状态栏界面的每次调用都必须独立于状态栏可能引发的任何事件,以避免引发条件的进一步问题。将状态栏界面想象成一个网站,可以从程序的其他部分调用它来推送和拉取信息。

于 2012-05-02T12:21:45.223 回答
2

是否拥有 StatusBar 类或 StatusBarManager 类并不是什么大问题。但是让你的应用程序中的许多类都知道 StatusBars 和 StatusBarManagers 是一个坏主意,它会导致强耦合,并且有朝一日可能会很痛苦。

如何?

想象一下,当前向状态栏报告状态的组件必须在另一个应用程序中重用——使用文本控制台报告状态?- 向多个地方报告状态?或 - 根本不报告状态!

最佳选择:-事件监听。在您的类上公开一个 Status Changed 事件(您可以使用回调),或者在您的类共有的现有共享资源上公开。其他方,例如您的状态栏,可以订阅该事件。并且应该在不再需要/有效的订阅时取消订阅,以防止泄漏,正如您所提到的!

- 由于您已标记 WPF,对于 WPF,具有依赖属性“StatusText”,可能看起来是另一个诱人的选择,当您有多个状态属性时,使用这种方法,您需要一种方法来确定哪个最能告诉您现在需要在您的状态栏上显示有趣的状态!这可能是绑定、多重绑定(blech、complexity)或依赖属性更改事件处理程序。

但是 - 我建议您尽可能将 DependencyObjects 和 DependencyProperties 限制在您的 UI 层。原因是它们隐式地依赖于 UI 线程上的 Dispatcher,因此无法轻松适应非 UI 杂务。

由于您的应用程序有许多不同的部分,您可能还会发现将这两者结合起来使用一些地方和另一个地方是合理的。

于 2012-05-03T07:17:47.203 回答
1

您可以简单地使用该Observer模式并将其StatusBar作为侦听器添加到您的 20 个对象中。这将消除单例并更好地遵循 SRP 和 DIP,但您必须考虑是否值得付出努力。如果间接增加了太多的复杂性并且依赖注入是不可能的,那么单例可能会更好。

public class StatusBar implements StatusListener {
}

public interface StatusListener {
   public statusChanged(String newStatus)
}
于 2012-05-02T13:38:05.307 回答
0

类将隐式依赖于任何使用单例,并显式依赖于构造函数中的任何参数。我建议向单例添加一个接口,因此只需将所需的方法公开给使用 IStatusBar 的类。这是更多的代码,但会简化单元测试。

于 2012-06-18T15:29:14.907 回答
-1

在不了解更多应用程序架构的情况下很难给出建议,但也许您应该考虑依赖注入。例如,将一个 StatusBar 实例传递给每个直接使用它的类的构造函数。

于 2012-05-02T13:16:25.650 回答