新类实例vs Singleton类vs静态方法

时间:2011-08-30 11:16:23

标签: design-patterns

我正在努力为这种情况选择完美的设计模式:

当我点击我的swing UI上的“浏览”按钮时,必须在Web浏览器上打开指定的URL。此功能在此实用程序类中实现,如下所示:

//inside action Listener of the browse button I call the openURL method of the below class

class webBrowserUtility(){
    void openURL(String url){
    ........
    }
}

设计模式方法

方法1)我可以继续创建上面类的新实例并调用openURL()。

方法2)Singleton:使WebbrowserUtility类成为单例并在内存中保留该类的静态实例,以便能够在需要时调用该方法。

方法3)静态方法:将openURL()方法设为静态,并根据需要调用WebbrowserUtility.openURL(url)。

在我的第一种方法中,我担心它可能效率低下,因为每次点击浏览按钮都会创建一个WebBrowserUtility类的新实例。我对选择2)和3)之间适应哪种方法感到困惑。在这种情况下,您能帮助我选择这三种设计模式中最好的吗?或者是否有更好的设计模式可以适应相同的?

6 个答案:

答案 0 :(得分:5)

你的问题没有最终正确答案。而且无需寻找那个。实际上,在为某些软件设计架构时应该理解的是:当你不知道什么是正确的时 - 只需使用抽象。然后,如果您最终了解您的初始实现不正确,您只需将其替换为另一个,而不必更改公共接口。

我的意思是在你的情况下它并不明显:从一方面你应该使用单例实例,因此不需要实例化许多实例,消耗更多内存并在对象创建上引入额外开销。但是从另一方面来说,您无法确定您的项目要求是否会发生变化 - 也许您必须在WebBrowserUtility服务中添加一些状态并同时拨打多个电话,为不同的消费者保留不同的状态,或者您甚至可能希望为您的类实现实例池。你无法预测未来,这就是你应该使用抽象的原因。

抽象对象实例化的最简单方法是使用静态工厂方法并像getInstance()一样调用它 - 就像你要实现单例一样,尽管如此不仅仅考虑单例实现 - 这只是对如何实例化它的抽象。现在你可以坚持使用单例,所以这个方法总会返回唯一的服务实例,不过将来,如果你需要改变类的创建方式,你只需更改getInstance()实现而不需要更改实际使用您服务的任何代码。因此,在您有足够的信息可供选择之前,您不必立即决定哪种方式更好。

使用factory methods实例化您的服务可以提供更大的灵活性,但是有更好的方法。如果您继续开发关于实例化抽象的这个想法,您将会理解通常您希望将创建代码从实际服务移到专用的factory class中,因为有时您希望以不同的方式为不同的实例化相同的服务手段。这个想法的进一步发展最终使用控制反转模式,这是如何创建服务实例并管理它们之间的依赖关系的最终答案。

如果您正在使用Java,请查看非常受欢迎的Spring framework,它允许您在配置文件中定义服务创建规则,因此如果您需要原型而不是单例,那么这只是一个问题更改该配置文件。

我也不鼓励将服务类实现为许多具有所需逻辑的静态方法。背后的原因 - 它现在可以简单快速地实现它,但是将来你的手将与定义静态方法的接口捆绑在一起。因此,如果您最终需要使用多个实例,则必须更改使用静态方法的使用者代码,因为静态签名位于您的界面中,而不仅仅是在您的实现中。相比之下,原型/单例之间的决定隐藏在实例化代码中,因此消费者并不关心如何创建实例 - 他们只是要求一个实例并获得它。

答案 1 :(得分:2)

在这种情况下,我个人会使用静态方法,因为你的openURL方法不使用任何类属性,因此不需要类实例来支持它。

答案 2 :(得分:2)

首先,我建议你不要过分担心在这个阶段出现性能/效率问题的可能性,除非你有一些具体的理由相信它会成为一个问题。等等,看看它是否 出现问题,然后相应地解决它。但你可能会发现没有什么可担心的。

所以,问题是,你的WebBrowserUtility是否使用了你班级的任何非静态成员变量(即实例数据)?

  • 如果确实如此,那么您必须采用方法1.并且每次都创建一个新实例。

  • 如果没有,那么我倾向于使用静态方法并使WebBrowserUtility成为静态类而不是实现单例。你不真的只需要一个实例,这就是单例模式的用途。静态类解决方案上的静态方法为您提供了所需的轻松访问。缺点是,如果您正在为此编写单元测试,那么正确地对静态方法进行单元测试是有问题的。

答案 3 :(得分:2)

就个人而言,我会选择方法3,因为只要本示例的范围扩展,似乎不需要存储对象状态,并且可以直接使用点击处理程序。

当然,这里的限制是你不能传递一个类的实例,因为你可能是一个单例,但是即使这是必要的,它也不太可能因为缺少状态而实际存在< em>要求通过单例来限制实例的数量,所以你可能不应该使用单例。

我希望这会有所帮助。

答案 4 :(得分:1)

单身人士过度使用是限制实例数量的一种方式,因为这并不像人们想象的那样频繁。我认为它们比使用静态方法更容易进行测试。使用静态方法意味着您无法轻松地将实际Web浏览器实用程序类交换为模拟或测试double。这是否是一个问题,由你决定。

我可能仍会在这里使用静态方法,如果需要修改WebBrowserUtility类以在内部使用单例实例,并允许客户端代码在需要时将此实例设置为测试版本。请参阅Working Effectively with Legacy Code中的“介绍静态设置器”。

答案 5 :(得分:0)

您是否需要在WebBrowserUtility类中保持状态(例如成员变量,计数器......)?

如果是:您是否需要此状态全局可用或同步?方法2 ...否则1)

如果否:那么这是一个简单的静态实用程序类,在静态类上使用静态方法