有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何在没有instanceOf的情况下实现LayoutManager?

对于我正在处理的特定布局,我需要制作自己的LayoutManager

它将根据组件的类型布置不同的组件:Label以一种方式布置,分隔符以另一种方式布置,其他所有组件以第三种方式布置

我可以很容易地实现这一点,并确定不同类型组件的不同位置,如果我采用以下方法:

private Dimension calculatePositionForComponent(Component component) {
  if (component instanceOf JLabel)
     ...
  if (component instanceOf JSeparator)
     ...
}

有没有更好的方法来做到这一点,而不使用instanceOf

(不,我不必自己做LayoutManager,但如果我做了,事情会变得非常简单;)

提前谢谢

/B


共 (4) 个答案

  1. # 1 楼答案

    我还建议使用某种接口/子类解决方案来封装不同组件的不同布局计算。我还将添加一些注册机制,以便灵活地进行未来的添加(如果您想为新组件类型实现另一个单独的行为)

    public interface PositionCalculator {
      Dimension calculatePositionForComponent(MyLayoutManager manager, Component component);
    }
    
    class JLabelCalculator implements PositionCalculator {
      public Dimension calculatePositionForComponent(MyLayoutManager manager, Component component) {
        // ...
      }
    }
    
    class JRadioButtonPosCalculator impements PositionCalculator {
      public Dimension calculatePositionForComponent(MyLayoutManager manager, Component component) {
        // ...
      }
    }
    
    // More classes ...
    
    
    class MyLayoutManager extends LayoutManager {
      private static HashMap<Class, PositionCalculator> calculators = new HashMap<Class, PositionCalculator>();
      public static registerPositionCalculator(Class c, PositionCalculator p) {
        calculators.put(c, p);
      }
      private static PositionCalculator defaultCalculator = new DefaultPositionCalculator(); // Not shown here ...
      // ...
      private Dimension calculatePositionForComponent(Component c) {
        PositionCalculator calc = calculators.get(c.getClass());
        if (calc == null)
          calc = defaultCalculator;
        return calc.calculatePositionForComponent(this, c);
      }
    }
    

    现在,您可以为所有组件注册单个位置计算器,方法是

    MyLayoutManager.registerPositionCalculator(JLabel.class, new JLabelCalculator());
    MyLayoutManager.registerPositionCalculator(JRadioButton.class, new JRadioButtonCalculator());
    // ...
    

    当然,此解决方案可能存在以下缺点:

    • 它可能比原来的慢
    • 它不适用于继承类:如果您有来自JLabel的子类,则必须单独注册它。解决方案可以适应这种情况,但这将以另一个性能损失为代价

    另一方面,该解决方案具有很好的可扩展性:您可以定义不同的布局行为,而无需接触MyLayoutManager类

  2. # 2 楼答案

    唯一其他实用的方法是使用多态性,并将函数calculatePositionForComponent()推送到组件接口/抽象类。这可以反过来使用来自实际布局管理器的数据,然后返回尺寸。根据calculatePositionForComponent()方法需要访问的数据类型,在特定情况下使用这种方法可能是不切实际的

    使用多个instanceof if子句时的一个技巧是使用if-else-if-else类型的样式。然后根据实际情况,将比较层次结构中最明显的选项上移,以加快if块的速度

  3. # 3 楼答案

    您可能希望将信息添加到约束对象中。作为奖励/惩罚,你会获得额外的间接层

    我更喜欢布局管理器界面向容器添加组件,而不是让容器向布局管理器添加组件的默认方式。这允许您以更自然的方式构造约束对象。在您的例子中,可以使用不同的方法来添加JLabelJSeparator等,这样您就不必重复信息,也可以使用不同的参数

  4. # 4 楼答案

    看起来instanceOf可能是最直接的方法。不能使用方法重载,因为方法重载是在编译时决定的。这意味着您不能只使用以下方法:

    private Dimension calculatePositionForComponent(JLabel component) {
        ....
    }
    private Dimension calculatePositionForComponent(JSeparator component) {
        ....
    }
    ....
    

    因为您仍然需要使用instanceOf和强制转换来获得在运行时调用的正确方法

    是的,使用instanceOf通常是一种代码味道,可能有一种更面向对象的方法来实现这一点。然而,对于这种特定的代码,我看到许多高级开发人员使用instanceOf。这是有原因的,而不仅仅是一根拐杖。有时它是完成这项工作的最佳工具。伊姆霍,这是其中一次