我正在努力为这种情况选择理想的设计模式:
当我在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){
........
}
}
Run Code Online (Sandbox Code Playgroud)
设计模式方法
方法1)我可以继续创建上述类的新实例,然后调用openURL()。
方法2)单例:使WebbrowserUtility类成为单例,并在内存中保留该类的静态实例,以便在需要时可以调用该方法。
方法3)静态方法:使openURL()方法为静态,并根据需要调用WebbrowserUtility.openURL(url)。
在我的第一种方法中,我担心它的效率可能不高,因为每次单击浏览按钮都会创建WebBrowserUtility类的新实例。我对选择2)和3)之间的哪种方法感到困惑。您能帮我在这种情况下从这三种设计模式中选择最好的吗?还是有一种更好的设计模式可以适应相同的需求?
您的问题没有最终的正确答案。无需寻找一个。实际上,在为某些软件设计体系结构时应该理解的是:当您不知道什么是正确的时,只需使用抽象即可。然后,如果您最终了解最初的实现方法不合适,则只需将其替换为另一个,而不必更改公共接口。
我的意思是说,这并不明显:从一侧来看,您应该使用一个单例实例,这样就无需实例化许多实例,消耗更多内存并在对象创建上引入额外的开销。但是从另一方面,您不能确定您的项目需求不会改变-也许您将不得不向服务中添加一些状态WebBrowserUtility并并行进行多次调用,以保持针对不同使用者的不同状态,或者甚至想要为您的类实现实例池。您无法预测未来,这就是为什么应该使用抽象。
抽象对象实例化的最简单方法是使用静态工厂方法并像这样来调用它getInstance()-就像您将要实现单例一样,尽管不要仅在单例实现方面考虑它-而是对如何实例化它的抽象。现在您可以坚持单例,因此此方法将始终返回服务的唯一实例,尽管将来,如果您需要更改类创建的方式,则只需更改getInstance()实现而无需更改任何实际的代码。使用您的服务。因此,在您有足够的信息可供选择之前,您不必立即决定哪种方法更好。
因此,使用工厂方法实例化服务将为您提供更大的灵活性,但是还有更好的方法。如果您继续开发有关实例化抽象的想法,您将理解通常您希望将创建代码从实际服务移到专用的工厂类中,因为有时您想以不同的方式以不同的方式实例化同一服务。这个想法的进一步发展最终使用了Inversion of Control模式,这是有关如何创建服务实例以及管理它们之间的依赖关系的最终答案。
如果您使用的是Java,请看一下非常流行的Spring框架,该框架允许您在配置文件中定义服务创建规则,因此,如果需要原型而不是单例,则只需更改该配置文件即可。
我也不鼓励将您的服务类实现为带有所需逻辑的许多静态方法。其背后的原因-现在可以轻松,快速地实现它,但是将来,您将被定义静态方法的接口所束缚。因此,如果最终需要使用多个实例,则还必须更改使用静态方法的使用者代码,因为静态签名位于接口中,而不仅仅是在实现中。相比之下,在原型/单例之间进行选择的决定被隐藏在实例化代码中,因此消费者不关心实例的创建方式,他们只是索要一个实例并获取它。
首先,我建议您在此阶段不要过度担心性能/效率问题的可能性,除非您有具体的理由相信这将是一个问题。等待,看看是否确实存在问题,然后相应地解决。但您可能会发现没有什么可担心的。
那么,问题是,您是否WebBrowserUtility使用了类的任何非静态成员变量(即实例数据)?
如果是这样,那么您必须采用方法 1. 并每次都创建一个新实例。
如果没有,那么我倾向于使用静态方法并创建WebBrowserUtility静态类,而不是实现单例。您实际上并不需要只有一个实例,这就是单例模式的用途。静态类解决方案上的静态方法为您提供了所需的轻松访问性。缺点是,如果您为此编写单元测试,正确地对静态方法进行单元测试是有问题的。