【问题标题】:Which design is a better? A singleton object or pass an object everytime? [closed]哪种设计更好?一个单例对象还是每次都传递一个对象? [关闭]
【发布时间】:2011-12-31 01:25:18
【问题描述】:

我有一个视图、控制器和模型。这是一个桌面应用程序,假设它是一个浏览器。因此,有一个名为 AppCurrentStatus 的对象。其中包含窗口位置、打开的窗口数量以及窗口内容。

假设用户想打开一个新标签,流程是这样的:

1. View (user interface) press new a tab.
2. Fire event to controller.
3. Controller update the AppCurrentStatus, add one new tab.
4. Controller notify the model, the model store the data, just in case the user close the browser incidentally 

问题是,视图、控制器和模型如何从 AppCurrentStatus 中获取它们需要的信息?我是否应该让 AppCurrentStatus 成为一个单例,让每个人都可以调用它。比如用户可以有3个以上的tab,controller可以直接通过单例调用,检查是否有3个tab。如果新选项卡添加成功,模型会在请求控制器时保存 AppCurrentStatus,只需从单例调用它。

另一种方法是将 AppCurrentStatus 作为变量保留在控制器中,当用户添加新选项卡时,该事件将触发并告诉控制器检查它自己的 AppCurrentStatus,如果是修改,只需将此对象传递给模型,以保存它。

更多的指定告诉不同,模型会这样,方法一:

-(void)save(); //calling singleton

如果方法二是这样的

-(void)save(AppCurrentStatus aAppCurrentStatus); //save from a object

或者可以提出其他更好的解决方案?

【问题讨论】:

    标签: oop object architecture


    【解决方案1】:

    我发现我的代码经常以单例开始。尽管我知道得更多——像这样的单例基本上是全局变量,而且我们都知道全局变量是不好的。

    但是,像这样编写一个单例代码并在需要的地方使用它是非常容易的。

    通常,在一段时间内 - 一个月左右 - 我最终会切换到“传递它”模式。通常是因为一开始是单身人士变得不止一个。例如。在我谋生的事情中,一个单例的 processor_under_test() 变成了多个处理器。

    在您的情况下,问问自己:您的单个应用(反映在 AppCurrentStatus 中)最终成为一组多个合作应用中的一个的可能性有多大?如果低,单例可能是最简单的方法。

    (与此相关,想想有多少单文档应用程序变成了多文档。)

    不要担心这个,要找到最好的方法。像这样的改变只是编程的一部分。有时你会从单例流向,我们可以称之为 N-ton。有时回来。

    然而,这里值得一提的是两个相关的模式。

    首先,当最初的单例变成 N-ary-ton 时,您无需立即放弃全局单例的易用性。相反,您可以创建一个主单例,我通常称之为“环境”之类的东西,它包含几个 N-ary-ton 对象或引用,可能还有其他东西。

    此外,如果您确实选择传递对象,则不一定只需要传递 AppCurrentStatus。因为您最终可能还需要传递其他内容。同样,我通常会传递一些我称之为 Environmrnt 的东西,它在不同的调用站点可能有不同的形状。


    最后两点:

    (1) 我愿意容忍在不适合重用的应用程序代码中使用单例。但是,我发现,如果我正在编写可能希望包含在库中并在其他地方重用的代码,那么依赖单例是不好的——因为其他地方可能不想让你的单例混乱.

    同样,出于某种原因,我发现为单例代码编写好的单元测试更加困难。我现在不记得所有的细节,但是,考虑一下:你如何测试几种不同的构造和破坏单例的方法?如果您的应用关闭时没有其他原因,您可能需要一个析构函数或终结器。

    由于这些原因,我经常创建两个类:

    内部类,在您的示例中,我可能将其称为 AppCurrentStatus。 以及外部类 AppCurrentStatus_singleton。

    可能对将使用单例的人隐藏内部类的实现,但将其公开,以便您可以编写一组好的单元测试。我经常这样做,以至于在 C++ 中我创建了一些模板来处理简单的情况:Singleton。

    (2) 最后,如果您关心性能,传递的参数越多,速度就越慢。而单例全局可能更快。

    对于大多数程序,这可能是一种无关紧要的过早优化。我只是考虑这类事情,因为性能是我的生计。

    相关的可维护性:虽然单例是全局变量,而且全局变量很糟糕,但我认为函数/方法的大参数列表更糟糕。我宁愿使用单例。但是参数对象设计模式可能会更好。


    好吧,我撒了谎:另一个支持单例的问题:有时您没有能力更改所有代码。例如。有时您将回调传递给某个库,该库最终会调用您的代码。您可能没有向此界面添加参数的选项。单身人士可以做到这一点。

    相关:任何进行回调的人都应该提供一个逃生舱口:一个通用对象引用或一个 cookie,回调操作库会传递它,但不会将语义归入其中。

    【讨论】:

      【解决方案2】:

      这个问题将两个不同的概念混为一谈:单例静态类

      使用静态类会起作用——所有状态数据都是静态存储的,可以从任何地方访问。但是,由于您的问题还强调面向对象的原则,因此我建议这不是首选方法,因为它限制了您未来的发展。静态类不适合依赖注入或被模拟或修饰。

      单例实现通常不受欢迎,但它为您的情况提供了一个很好的解决方案 - 就您传递变量而言,它是两全其美的方法,但它们都指向同一个单一对象。这样,如果您想创建单元测试,您仍然可以使用装饰器或模拟组件,但所有控制器最终都会引用并访问相同的状态信息。

      【讨论】:

        【解决方案3】:

        我建议您使用工厂方法来获取 AppCurrentStatus 值的实例,并在每次需要访问它时调用它。

        AppCurrentStatusHolder.getAppCurrentStatus()
        

        现在在开始时您可以使用单例,但稍后如果您需要更改策略,那么您与实施的耦合度就会降低。

        【讨论】:

          猜你喜欢
          • 2011-03-27
          • 2012-07-07
          • 1970-01-01
          • 1970-01-01
          • 2013-02-02
          • 1970-01-01
          • 2022-12-14
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多