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

时间:2010-09-27 18:50:14

标签: java inheritance interface polymorphism if-statement

我正在尝试编写一个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语句来确定用户在运行时选择的布局?

谢谢!

9 个答案:

答案 0 :(得分:17)

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

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

这种分散的逻辑:

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();

答案 1 :(得分:3)

由于java没有第一类函数,因此可以使用接口来包装。

LayoutHandler ~> Interface

LayoutHandlerA, LayoutHandlerB, etc implements LayoutHandler

Map<String, LayoutHandler> handlers = new HashMap<...>();

LayoutHandler handler = handlers.get(userSelectedLayout);

handler.handle();

答案 2 :(得分:2)

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

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

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

每个布局都有不同类的想法并不错。这很像traits class的概念。看看那个。这对你的设计很有帮助。

答案 3 :(得分:2)

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

伪码

 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语句。

答案 4 :(得分:1)

某处,某处需要指定实现。这可能是源代码中的if语句链 - 但它也可能是其他东西;例如,在外部数据源中指定的类名,通过反射实例化。

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

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

答案 5 :(得分:1)

我对你的代码架构“有点模糊”,但想法是你只在一个的地方切换,而不是在你的代码中散布多个具有相同功能的交换机除了正在操作的对象之外的签名。

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

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

答案 6 :(得分:1)

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

可以肯定的是,有一些方法可以避免那些初始化if语句,但你必须确定适合你的应用程序的复杂程度和可能性的可能性。

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

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

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

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

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

  3. 应用程序通过在列表中的每个驱动程序上调用Class.forName()来初始化。每个驱动程序都知道在Class.forName()

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

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

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

答案 7 :(得分:1)

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

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

答案 8 :(得分:0)

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

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