2011-08-30 100 views
2

我奋力选择此方案的完美设计模式:新的类实例VS Singleton类VS静态方法

当我点击我的挥杆UI的浏览按钮,指定的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)之间的适应方法感到困惑。你能帮我选择这三种设计模式中最好的一种吗?还是有更好的设计模式可以适应相同的?

+0

那么,['Desktop.browse()'](http://download.oracle.com/javase/7/docs/api/java/awt/Desktop.html#browse(java.net.URI))已选择方法2. –

回答

2

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

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

  • 如果确实如此,那么您必须按照方法1进行操作,并且每次都创建一个新实例。

  • 如果没有,那么我会倾向于使用静态方法,并使WebBrowserUtility为静态类而不是实现单例。你不需要真的需要只有一个实例,这是单身模式的用途。静态类解决方案的静态方法为您提供了所需的易用性。不足之处在于,如果你正在为此编写单元测试,那么对静态方法进行适当的单元测试是有问题的。

+1

+1用于考虑测试。 – jstephenson

2

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

0

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

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

如果没有:那么这是一个简单的静态实用工具类,去一个静态方法的静态类

2

个人而言,我会选择的方法3,如只要这个例子的范围扩大,有没有出现任何需要存储的对象状态,并有从单击处理直接使用。

当然,这里的局限性是,你不能像在单例中那样绕过类的一个实例,但即使这是必要的,也不可能因为它缺少状态而实际上会存在要求通过一个单独限制实例的数量,所以你可能不应该使用反正单身。

我希望这会有所帮助。

+0

从我+1,因为[你和我本质上是说同样的事情](http://stackoverflow.com/questions/7242297/new-class-instance-vs-singleton-class-vs-static-method/7242406 #7242406)。 – razlebe

1

单身人士滥用为限制实例数量的方式,因为这是没有必要经常像一些人认为。我认为它们比静态方法更容易作为一种测试方法。使用静态方法意味着您不能轻松地将您的真实Web浏览器实用程序类用于模拟或测试加倍。这是否是一个问题是由你来决定的。

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

4

有没有最终正确回答你的问题。不需要寻找那个。其实什么而对于一些的软件设计架构应该明白的是:当你不知道做正确的事情 - 只是用一种抽象。那么如果你最终会理解你最初的实现是不正确的,那么你只需将它替换为另一个,而不必改变公共接口。

我的意思是在你的情况并不明显:从一个侧面,你应该用一个单一实例去那么无需实例很多情况下,占用更多的内存和对象的创建引入额外的开销。然而从另一个侧面,你不能确定你的项目的要求不会改变 - 也许你会有一些状态添加到您的WebBrowserUtility服务,使许多并行调用保持的状态不一样不同消费者的,或者可能甚至想为您的课程实施实例池。你无法预测未来,这就是为什么你应该使用抽象。

抽象的对象实例化的最简单方法是使用静态工厂方法并调用它像getInstance() - 就像如果你要实现一个单身,但不只是在条款想想单例实现 - 这仅仅是如何实例化它的抽象。现在你可以坚持使用单例,所以这种方法将永远返回服务的唯一实例,但是在将来,如果你需要改变类的创建方式,你将只需更改getInstance()实现,而无需更改任何代码实际上使用您的服务。所以你不必现在决定哪种方式更好,直到你有足够的信息来选择。

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

如果您使用的是Java,看看非常流行的Spring framework,允许您定义配置文件服务创建的规则,所以如果你需要一个原型而不是单例,这只是改变这种的问题配置文件。

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