Java:使用多态来避免if语句?

我正在尝试编写一个java程序,根据用户选择的内容初始化某些布局。 我想要做的是尽量避免编写一堆if语句,这样如果需要添加更多布局,代码可以扩展以备将来使用。 我听说实现这个的最好方法是使用多态,但我对多态的理解仍然有点模糊。

说我想实现这个案例:

if (user choose layoutA) { initialize layoutA } if (user choose layoutB) { initialize layoutB } if (user choose layoutC) {initialize layoutC } 

我正在考虑为要实现的类创建一个接口。 令我困惑的是它在main()中是如何工作的,我是否还需要条件if或switch语句来确定要实例化哪个类?

 interface LayoutHandler { public void initializeLayout(); } class layoutA implements LayoutHandler { public void initialize Layout {initialize layout A} } class layoutB implements LayoutHandler { public void initialize Layout {initialize layout B} } class layoutC implements LayoutHandler { public void initialize Layout {initialize layout C} } 

然后在主要的某个地方:

 public static void main() { getlayoutselectionfromuser() if (user choose layoutA) { LayoutHandler layout = new layoutA(); } if (user choose layoutB) { LayoutHandler layout = new layoutB(); } if (user choose layoutC) { LayoutHandler layout = new layoutC(); } } 

我是否仍然需要在主程序中使用switch或if语句来确定用户在运行时选择的布局?

谢谢!

通常,在某些时候很难避免某种条件语句来创建适当类的实例。

当多个地方有多个if-else语句时,就会产生多态性的好处。 多态性为您封装了条件逻辑。 有关此主题的其他讨论,请参阅此问题 。

这种分散的逻辑:

 void initLayout() { if (user choose layoutA) { initialize layoutA } if (user choose layoutB) { initialize layoutB } if (user choose layoutC) {initialize layoutC } } void refreshLayout() { if (user choose layoutA) { refresh layoutA } if (user choose layoutB) { refresh layoutB } if (user choose layoutC) { refresh layoutC } } void cleanupLayout() { if (user choose layoutA) { cleanup layoutA } if (user choose layoutB) { cleanup layoutB } if (user choose layoutC) { cleanup layoutC } } 

获取替换为更简单的东西:

  layout = getLayout(user choice); layout.initLayout(); layout.refreshLayout(); layout.cleanupLayout(); 

由于java没有第一类函数,因此可以使用接口进行环绕。

 LayoutHandler ~> Interface LayoutHandlerA, LayoutHandlerB, etc implements LayoutHandler Map handlers = new HashMap<...>(); LayoutHandler handler = handlers.get(userSelectedLayout); handler.handle(); 

简而言之,是的。 你需要ifs或一些映射机制。

您需要一些方法将用户的输入转换为您想要的类。 你的代码中的ifs工作得很好,清晰可读。 你也可以使用开关。

可以避免这种情况,但是你最终会混淆你的代码,最终可能会有类似if的东西。 您必须定义从用户输入到对象的映射; 这是无法规避的。 最清晰,最可维护的方法就是你已经拥有的东西(虽然我会把其他ifs放在那里。:))

你对每个布局都有不同类的想法也不错。 这很像一个特质类的概念。 看看那个。 它对您的设计很有帮助。

不。使用地图。 当你得到选择时,只需在地图中查找处理程序然后离开即可。

伪码

  Map handlers = new Map() handlers.put(layoutA, HandlerForA) // more handlers, possibly use dependency injection Layout chosen = user choose layout // get a ref to the selected layout Handler handler = handlers.get(chosen) if (handler == null) { // No HandlerException } handler.go() 

只有一个if语句。

某个地方需要指定实施。 这可能是源代码中的if语句链 – 但它也可能是其他东西; 例如,在外部数据源中指定的类名,通过reflection实例化。

对于某些接口,可能会有比实例化更多的接口调用。 多态性可以减少与特定实现的耦合。

这种减少的耦合可以帮助使代码更易于维护。 您可以添加新实现,而无需修改可能的许多调用方。

我在你的代码架构上“模糊不清”,但想法是你只在一个地方放置了交换机,而不是在你的代码中散布多个交换机,这些交换机除了正在运行的对象之外具有相同的function签名。

确切的实现取决于你的目标是什么,但我认为你会有一个实现LayoutHander的类,并且有一个对Layout的成员引用。 当用户选择他的布局时,多态性在这里保持,而不是现在的等级。 也就是说,如果定义不同行为的对象是“布局”,那么您需要使布局具有多态性,而不是LayoutHander。

当您考虑多态性时,请考虑重用代码。 “这些相关的function与不同的对象有什么共同之处?”

我认为使用if语句进行初始化很好。 您试图避免在整个程序中重复使用if语句来“选择”行为。 使用if语句进行一次初始化很好。

可以肯定的是,有一些方法可以避免那些初始化if语句,但你必须决定什么级别的复杂性和可能的​​可读性损失适合你的应用程序。

例如,以下是解决此问题的一些方法,从简单到复杂:

  • 使用那些初始化if语句
    • 使用硬编码引用直接在程序逻辑中实现类(更难找到)
  • 使用可能的实现类初始化一些数据结构(例如Map)
    • 仍然是对实现类的硬编码引用
    • 通常更容易添加更多的实现类
    • 代码有点复杂和抽象,无法理解和调试
  • 使用动态注册
    • 没有对应用程序中的实现类的硬编码引用
    • 需要更多设置
    • 在不知道如何设置注册工作的情况下,代码更难理解

最后一个方法(动态注册)的一个很好的例子是查看JDBC的工作原理。 使用Class.forName()在应用程序中注册JDBC驱动程序,然后使用JDBC URL选择特定的JDBC驱动程序。 这是一个典型的工作流程:

  1. 潜在目标JDBC驱动程序添加了类路径。

  2. 应用程序配置了这些驱动程序的列表,例如通过在属性文件中列出JDBC驱动程序。

  3. 应用程序通过在列表中的每个驱动程序上调用Class.forName()来初始化。 当Class.forName()加载时,每个驱动程序都知道用DriverManager注册自己

  4. 应用程序确定要使用的目标数据库资源,并将其解析为JDBC URL,例如在配置对话框或用户提示中。

  5. 应用程序根据目标JDBC URL向DriverManager请求连接。 DriverManager轮询每个已注册的驱动程序,以查看它是否可以处理目标JDBC URL,直到DriverManager找到有效的URL。

这将是避免那些if语句的相反极端。

“..如果需要添加更多布局,以供将来使用”

我还建议你研究工厂模式。 如果在工厂中包含此条件逻辑,它应该有助于降低维护和可读性。

您应该使用框架来避免创建o定义行为。

Spring让我们可以管理和解决这个问题。 它使用工厂模式和更多设计模式。 因此,使用注释或xml配置文件,您可以决定创建哪些类。 PD:当然,我是100%安全,spring使用if。 但它已被certificate并用于许多强大而可靠的应用程序中。