我有一个视图,控制器和模型。这是一个桌面应用程序,假设它是一个浏览器。所以,有一个名为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个以上的选项卡,控制器可以通过单例直接调用它,以检查它是否有3个选项卡。如果成功添加了新选项卡,模型是否可以在询问控制器时保存AppCurrentStatus,只需从单例中调用它即可。
另一种方法是将AppCurrentStatus保持为控制器中的变量,当用户添加新选项卡时,事件将触发并告诉控制器检查自己的AppCurrentStatus,如果是修改,只需将此对象传递给模型,即可保存它。
更多指定告诉不同的,模型会喜欢这样,接近一个:
-(void)save(); //calling singleton
如果方法二是这样的话
-(void)save(AppCurrentStatus aAppCurrentStatus); //save from a object
或其他更好的解决方案可以建议吗?
答案 0 :(得分:2)
我发现我经常用单例开始编写代码。虽然我知道的更好 - 像这样的单身人士基本上是全球性的,而且我们都知道全局变量很糟糕。
但是,编写像这样的单例非常简单 ,并在必要时使用它。
通常,在一段时间内 - 一个月左右 - 我最终会切换到“传递它”模式。通常因为最初只是一个单身人士。例如。在我为生者所做的事情中,单身处理器_under_test()成为多个处理器。
在您的情况下,问问自己:在AppCurrentStatus中反映的单个应用程序最终会成为多个合作应用程序集之一的可能性是多少?如果低,单身可能是简单的方法。
(与此相关,请考虑有多少单个文档应用程序成为多个文档。)
不要担心这一点,关于找到最好的方法。像这样的变化只是编程的一部分。有时你会从单身人士流向我们称之为N吨的单身人士。有时回来。
但是,值得一提的是两个相关的模式。
首先,当单身人士开始成为N-ary-ton时,你不需要立即放弃全球单身人士的易用性。相反,你可以创建一个主单例,我通常称之为“environ”,它包含几个N-ary-ton对象或引用,可能还有其他东西。
此外,如果您确实选择传递对象,则不一定需要仅传递AppCurrentStatus。因为你最终可能还需要传递别的东西。同样,我经常传递一些我称之为Environmrnt的东西,在不同的呼叫站点可能会有不同的形状。
最后两个笔记:
(1)我愿意容忍在不适合重用的应用程序代码中使用单例。但是,我发现如果我编写的代码很可能想要包含在库中并在其他地方重用,那么取决于单例是不好的 - 因为其他地方可能不想让你的单例混乱
同样,出于某种原因,我发现为单例代码编写好的单元测试更加困难。我现在不记得所有的细节,但是,考虑一下:你如何测试构建和破坏单身的几种不同方法?而且你可能想要一个析构函数或终结器,如果除了你的应用程序关闭之外别无其他原因。
由于这些原因,我经常创建两个类:
内部类,在您的示例中,我可以调用AppCurrentStatus。 和外部类AppCurrentStatus_singleton。
可能会隐藏将要使用单例的人的内部类的实现,但是暴露它以便您可以编写一组良好的单元测试。我经常这样做,在C ++中我创建了一些模板来完成简单的案例:Singleton。
(2)最后,如果你关心性能,传递的参数越多,速度就越慢。单身全球可能更快。
对于大多数程序来说,这可能是一个不在乎,过早优化的问题。我只是考虑那种事情,因为表演是我的面包和黄油。
相关的,可维护性:虽然单例是全局的,而且全局变量很糟糕,但我认为函数/方法的大参数列表更糟糕。我宁愿使用单身人士。但Paramater Object desiogn模式可能更好。
好吧,我说谎了:另一个支持单身人士的问题:有时候你没有能力改变所有的代码。例如。有时您会将回调传递给某些库,最终会调用您的代码。您可能无法选择向此接口添加参数。单身就可以做到这一点。
相关:任何进行回调的人都应该提供一个转义填充:回调操作库传递的通用对象引用或cookie,但不会将语义归结为。
答案 1 :(得分:0)
这个问题混淆了两个不同的概念: singleton 和 static class 。
使用静态类将起作用 - 所有状态数据都是静态存储的,可以从任何地方访问。既然你的问题也强调了面向对象的原则,我会建议这不是受欢迎的方法,因为它限制了你未来的发展。静态类不适合依赖注入或被嘲弄或修饰。
单例实现通常不受欢迎,但为您的案例提供了一个很好的解决方案 - 只要您传递变量,它就是两个世界中最好的,但它们都指向相同的单个对象。这样,如果要创建单元测试,仍然可以使用装饰器或模拟组件,但所有控制器最终都会引用并访问相同的状态信息。
答案 2 :(得分:0)
我建议您使用工厂方法获取AppCurrentStatus值的实例,并在每次需要访问它时调用它。
AppCurrentStatusHolder.getAppCurrentStatus()
现在在开始时你可以使用单例,但是如果你需要更改策略,那么你就不会再与实现相结合了。