1

对于我正在处理的某个布局,我需要制作自己的LayoutManager.

它将根据它们的类型来布置不同的组件:Labels 以一种方式,Separators 以另一种方式,以及其他所有方式以第三种方式。

如果我制定一个方法,我可以轻松实现这一点并确定不同类型组件的不同位置:

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

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

(不,我不必自己做LayoutManager,但如果我这样做的话,事情会变得非常容易;))

提前致谢

/乙

4

4 回答 4

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

现在,您可以为所有组件注册单独的 PositionCalculators,方法是:

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

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

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

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

于 2009-04-01T07:18:47.627 回答
1

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

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

于 2009-04-01T09:26:40.487 回答
0

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

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

于 2009-04-01T06:11:30.063 回答
0

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

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

因为您仍然必须使用instanceOf和强制转换才能在运行时调用正确的方法。

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

于 2009-04-01T06:18:28.423 回答