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

时间:2009-04-01 06:01:34

标签: java oop instanceof layout-manager

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

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

如果我制作方法,我可以很容易地实现这个并确定不同类型组件的不同位置:

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

有没有更好的方法来执行此操作,而不使用instanceOf

(不,我不需要自己制作LayoutManager,但如果我这样做会让事情变得非常容易;))

提前致谢

/ B

4 个答案:

答案 0 :(得分: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);
  }
}

现在,您可以通过

为所有组件注册单独的PositionCalculator
MyLayoutManager.registerPositionCalculator(JLabel.class, new JLabelCalculator());
MyLayoutManager.registerPositionCalculator(JRadioButton.class, new JRadioButtonCalculator());
// ...

当然,这种解决方案可能会遇到以下缺点:

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

另一方面,该解决方案具有很好的可扩展性:您可以在不触及MyLayoutManager类的情况下定义不同的布局行为。

答案 1 :(得分:1)

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

我的首选是布局管理器接口将组件添加到容器,而不是让容器向布局管理器添加组件的默认方式。这允许您以更自然的方式构造约束对象。在您的情况下,您可以使用单独的方法添加JLabelJSeparator等,这样您就不必重复信息并且可以有不同的参数。

答案 2 :(得分:0)

唯一的另一种实用方法是使用多态并将函数calculatePositionForComponent()推送到组件接口/抽象类。这可以反过来使用来自实际布局管理器的数据,然后返回Dimensions。在您的特定情况下使用此方法可能是不切实际的,具体取决于calculatePositionForComponent()方法需要访问哪种数据。

使用多个instanceof if子句时的提示是使用if-else if-else if-else类型样式。然后根据实际情况,在比较层次结构中移动最明显的选择,以使if-block更快。

答案 3 :(得分:0)

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

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

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

是的,使用instanceOf通常是代码味道,并且可能有更多OOP方式来执行此操作。但是,对于这种特定类型的代码,我看到许多高级开发人员使用instanceOf。它出于某种原因而不仅仅是作为一个拐杖。有时它是这项工作的最佳工具。恕我直言,这是其中一次。