java - 覆盖 getPreferredSize() 会破坏 LSP

标签 java swing jcomponent liskov-substitution-principle

我总是在这个网站上看到覆盖 getPreferredSize() 而不是使用 setPreferredSize() 的建议,如这些先前线程中所示。

  1. Use of overriding getPreferredSize() instead of using setPreferredSize() for fixed size Components
  2. Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?
  3. Overriding setPreferredSize() and getPreferredSize()

看这个例子:

public class MyPanel extends JPanel{

  private final Dimension dim = new Dimension(500,500); 

  @Override
  public Dimension getPreferredSize(){
      return new Dimension(dim);
  }

 public static void main(String args[]){
      JComponent component = new MyPanel();
      component.setPreferredSize(new Dimension(400,400));
      System.out.println(component.getPreferredSize());
 }

}

setPreferredSize()

  • Sets the preferred size of this component.

getPreferredSize()

  • If the preferredSize has been set to a non-null value just returns it. If the UI delegate's getPreferredSize method returns a non null value then return that; otherwise defer to the component's layout manager.

这样做显然会破坏 Liskov Substitution Principle .

prefferedSize 是一个绑定(bind)属性,因此当您设置它时,将执行 firePropertyChange。所以我的问题是,当您覆盖 getPrefferedSize() 时,您是否也需要覆盖 setPreferredSize(..)

示例:

 public class MyPanel extends JPanel{

  private Dimension dim = null; 

  @Override
  public Dimension getPreferredSize(){
      if(dim == null)
       return super.getPreferredSize();
      return new Dimension(dim);
  }

  @Override
  public void setPrefferedSize(Dimension dimension){
        if(dim == null)
            dim = new Dimension(500,500);
        super.setPreferredSize(this.dim); //
  }

 public static void main(String args[]){
      JComponent component = new MyPanel();
      component.setPreferredSize(new Dimension(400,400));
      System.out.println(component.getPreferredSize());
 }

}

现在我们看到我们得到了相同的结果,但监听器将收到真实值的通知,而且我们不会破坏 LSP,因为 setPreferredSize 状态 设置此组件的首选大小。 但不是如何。

最佳答案

这个有趣问题的几个方面(Mad 已经提到了 spare-my-fellow-developer)

我们是否在仅覆盖 getXXSize() 时违反了 LSP(相对于 setXXSize() 也是如此)?

如果我们做对了 :-) 第一个权威是属性的 API 文档,最好从它的来源开始,即组件:

Sets the preferred size of this component to a constant value. Subsequent calls to getPreferredSize will always return this value.

这是一个有约束力的契约(Contract),因此无论我们如何实现 getter,它都必须遵守 constant 值(如果已设置):

@Override
public Dimension getPreferredSize() {
    // comply to contract if set
    if(isPreferredSizeSet())
        return super.getPreferredSize();
    // do whatever we want
    return new Dimension(dim);
}

XXSize 是绑定(bind)属性 - 是吗?

在 JComponent 的祖先中只有间接证据:实际上,Component 在 setter 中触发 PropertyChangeEvent。 JComponent 本身似乎记录了这个事实(由我加粗):

@beaninfo preferred: true bound: true description: The preferred size of the component.

这是……完全错误的:作为绑定(bind)属性意味着只要值发生变化就需要通知监听器,即必须通过以下(伪测试):

JLabel label = new JLabel("small");
Dimension d = label.getPreferredSize();
PropertyChangeListener l = new PropertyChangeListener() ...
    boolean called;
    propertyChanged(...) 
        called = true;
label.addPropertyChangeListener("preferredSize", l);
label.setText("just some longer text");
if (!d.equals(label.getPreferredSize())
   assertTrue("listener must have been notified", l.called); 

...但是失败了。出于某种原因(不知道为什么这可能被认为是合适的)他们希望 xxSize 的 constant 部分成为绑定(bind)属性——这样的覆盖根本不可能。可能(当然是胡乱猜测)一个历史问题:最初,setter 仅在 Swing 中可用(出于充分的理由)。在它向 awt 的反向移植中,它变成了一个从未有过的 bean 属性。

关于java - 覆盖 getPreferredSize() 会破坏 LSP,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21052894/

相关文章:

java - 在 Java 中更新单行数据库

java - 从 Excel 文件读取数字 - Java - Swing

java - 代码不适用于 Swing 图像按钮

java - 在 JFrame 上的 JPanel 内显示 JComponent

java - 如何创建自定义 Swing 组件

java - 在android studio 2.1中导入http包时出错

java - 最佳买卖股票修改版

java - RMI 多个客户端 - 每个客户端都有一个服务器对象

java - "Comparison method violates its general contract!"

java - 当组件在paintComponent()外部加载图像时,JFrame显示为空白;方法