Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Design patterns 如何在实践中避免/重构糟糕的单例?_Design Patterns_Oop - Fatal编程技术网

Design patterns 如何在实践中避免/重构糟糕的单例?

Design patterns 如何在实践中避免/重构糟糕的单例?,design-patterns,oop,Design Patterns,Oop,在仔细阅读了关于单身的事实(代码气味,而不是模式)之后,我想知道: 我如何重构代码以摆脱它们 尽管几乎所有人都认为糟糕的单身汉是糟糕的,但我找不到任何实用的建议来取代他们。要么很琐碎,要么很难 我可以想出一些方法,但所有这些似乎都极大地膨胀了我的代码 例如,假设我有一个“global”AppConfig类,它保存有关产品的许可证信息,并描述用户可用的功能 我能想到的是: 为包含AppConfig实例的每个项目类创建一个公共基类。(坏:对于已经有基类的情况不可能,例如表单) 使用setAppCo

在仔细阅读了关于单身的事实(代码气味,而不是模式)之后,我想知道:

我如何重构代码以摆脱它们

尽管几乎所有人都认为糟糕的单身汉是糟糕的,但我找不到任何实用的建议来取代他们。要么很琐碎,要么很难

我可以想出一些方法,但所有这些似乎都极大地膨胀了我的代码

例如,假设我有一个“global”
AppConfig
类,它保存有关产品的许可证信息,并描述用户可用的功能

我能想到的是:

  • 为包含
    AppConfig
    实例的每个项目类创建一个公共基类。(坏:对于已经有基类的情况不可能,例如表单)
  • 使用
    setAppConfig
    方法创建公共接口
  • 创建一个全局
    AppConfigFactory
    ,它可以创建
    AppConfig
    实例(坏:只会将问题转移到另一个类)
  • 将实例作为参数传递给每个需要它的方法。(错误:代码膨胀)
我能做什么


编辑:澄清:我在代码中发现了一个错误的单例。现在我想重构我的代码来删除它。我想了解一下如何做到这一点的技巧和一般想法。

让这个类只有静态成员怎么样?比如,代替这个(C代码):

这样做:

static class AppConfig
{
    public static string SomeConfigParam { get; set; }
}

只有在需要将类似实例的参数传递给集合中的函数或值时,单例才有意义。NET中的System.DBNull是一个很好的单例示例。如果它只是一个每个人都应该能够访问的全局数据存储,那么静态类会使您的代码更短、更简单。

使用依赖项注入和控制框架反转-这可能需要大量重构。然后,使用构造函数或属性依赖,请求“单例”-理想情况下,您不会要求全部内容,因为根据Demeter的原则,它应该只请求它真正需要的内容(在您的情况下是许可证信息)

我试图区分Singleton(反模式伪装全局变量)和Singleton(意味着您只需要其中一个变量)。真正的单例在程序开始时(或在工厂中)创建一次,并传递给需要它的对象。

你说

创建可以创建AppConfig实例的全局AppConfigFactory(错误:只会将问题转移到另一个类)

在我看来,这其实一点也不坏。客户机的观点是,他要求工厂对象提供他应该使用的配置。他不知道那是单身汉!一下子,单子就被封装在工厂里。[从实际角度看,工厂本身很可能最终成为一个单身汉,但一切都需要引导,对吗?]

现在,使用依赖项注入技术包装工厂访问是否是一种改进,其基本原理是只有一个对象负责创建这些AppConfig对象,只有工厂知道是否有一个或多个


这让我想到另一个宠物理论。。。没有像1这样的数字,当你开始时它看起来像一个单例,然后复杂度增加,你会发现一个场景,你的应用程序的某些部分(例如)使用一个配置,而另一部分使用另一个配置(例如,在版本之间的动态转换中)。工厂可以隐藏这种复杂性。

如果对象在其整个生命周期中都需要应用程序配置,则可以通过
setAppConfig()
方法或构造函数传递
AppConfig
。如果全局
AppConfig
与对象之间的关联是有条件的(即,仅在某些方法中需要),则将其作为一个额外参数传递。

看起来像是重复的,它不是重复的,至少不是您退出的问题的重复。我不想知道单身汉的正确用法或利弊。我有一个不好的单例,我想删除它,我想知道最好的方法。单例设计模式和单例代码气味之间有什么区别?单例代码气味本质上是对单例模式的滥用:请注意,静态类会使代码更难测试。但是如果它是一个简单的数据存储,这里就不是这样了。那不是仍然是一个单例吗?不,它更像是全局变量,只是有一个很好的名称空间前缀。面对现实——在每个程序中都会有一些全局变量。需要在程序范围内访问的设置和数据。静态类/类成员是以OOP方式封装这些类的最佳方式。全局变量也不错。只有当你滥用它们做不需要在程序范围内可用的事情时,它们才是坏的。但这是全球数据。不要试图假装没有全局数据。这是另一种代码味道/糟糕的做法/等等。当然,您可以以这样一种方式编写代码,即在任何地方都不会使用
静态
关键字。但这只会使它复杂化,并降低它的可维护性。就像生活中的每件事一样——避免极端。不要过度使用全局数据,也不要使用不足。在真正有意义的地方使用它,在地狱里没有雪球般的机会需要复制它(如应用程序配置的示例)。你只是不理解单例设计模式,你应该始终使用设计模式!!我真的不知道。你是在讽刺吗?你能给这些框架举一些例子吗?我可以用谷歌搜索一些关键词吗?这取决于你的语言。对于Java,有Spring和GUICE。对于.Net,有Spring.Net。可能还有其他的。但是即使你使用了IoC框架,你仍然需要持有或访问主容器对象的一些方式-它要么需要存储在静态类中,要么作为参数传递。。。所以
static class AppConfig
{
    public static string SomeConfigParam { get; set; }
}