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

Java:使用多态性避免if语句?,java,inheritance,interface,polymorphism,if-statement,Java,Inheritance,Interface,Polymorphism,If Statement,我试图编写一个java程序,根据用户选择的内容初始化某些布局。我想做的是尽量避免编写一堆if语句,这样,如果需要添加更多布局,代码就可以扩展以供将来使用。我听说实现这一点的最好方法是使用多态性,但我对多态性的理解仍然有点模糊 假设我想实施这个案例: if (user choose layoutA) { initialize layoutA } if (user choose layoutB) { initialize layoutB } if (user choose layoutC) {ini

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


谢谢

简而言之,是的。你需要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语句——但也可能是其他内容;e、 例如,外部数据源中指定的类名,通过反射实例化

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


这种减少的耦合有助于提高代码的可维护性。您可以添加一个新的实现,而无需修改潜在的许多调用者

一般来说,在创建适当类的实例时,很难避免某些类型的条件语句

当您在多个位置有多个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();
我对您的代码体系结构有点“模糊”,但我的想法是,您只在一个地方有开关,而不是在您的代码中散布多个开关,这些开关除了操作对象之外,具有相同的函数签名

确切的实现取决于您的目标是什么,但我认为您应该有一个实现LayoutAnder的类,并且有一个对布局的成员引用。当用户选择他的布局时,多态性在这里起作用,而不是像现在这样的级别。也就是说,如果定义不同行为的对象是“布局”,则需要使布局多态,而不是LayoutAuthAnder


当你想到多门主义时,想想代码重用。“这些相互关联但又不同的对象共享哪些共同的函数集?”

由于java没有一流的函数,您可以使用接口来包装

LayoutHandler ~> Interface

LayoutHandlerA, LayoutHandlerB, etc implements LayoutHandler

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

LayoutHandler handler = handlers.get(userSelectedLayout);

handler.handle();
layouthHandler~>接口
LayoutHandlerA、LayoutHandlerB等实现LayoutHandler
Map handlers=newhashmap();
layouthHandler handler=handlers.get(userSelectedLayout);
handle.handle();

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

可以肯定的是,即使是那些初始值设定项if语句,也有一些方法可以避免,但你必须决定什么样的复杂程度和可读性的可能损失适合你的应用程序

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

  • 使用那些初始值设定项if语句
    • 使用硬编码引用直接在程序逻辑中实现类(较难找到)
  • 使用可能的实现类初始化某些数据结构(例如Map)
    • 仍然是对实现类的硬编码引用
    • 通常更容易添加更多实现类
    • 代码更复杂,更抽象,更难理解和调试
  • 使用动态注册
    • 没有对应用程序中实现类的硬编码引用
    • 需要更多的设置
    • 如果不知道注册是如何设置的,代码就很难理解
最后一种方法(动态注册)的一个很好的例子是查看JDBC是如何工作的。JDBC驱动程序使用
Class.forName()
在应用程序中注册,然后使用JDBC URL选择特定的JDBC驱动程序。以下是一个典型的工作流:

  • 潜在的目标JDBC驱动程序添加到类路径中

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

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

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

  • 应用程序会根据请求请求DriverManager建立连接