我经常在此站点上看到有关覆盖getPreferredSize()的建议,而不是使用例如前面这些线程中所示的setPreferredSize()的建议。

  • Use of overriding getPreferredSize() instead of using setPreferredSize() for fixed size Components
  • Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?
  • 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()

    getPreferredSize()


    因此,这样做显然会破坏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状态为Sets the preferred size of this component.,但不是方法。

    最佳答案

    这个有趣问题的几个方面(疯子已经提到了我的同伴开发者)

    我们是否仅覆盖getXXSize()(也与setXXSize()一样)违反了LSP?

    如果我们没有正确执行操作,则不是这样:-)第一权限是属性的API文档,最好是从属性的起源开始,即Component:



    这是一个有约束力的契约(Contract),因此,我们实现的 setter/getter 必须遵守常量(如果设置):

    @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本身似乎在记录事实(由我自己负责):



    ……这是很明显的错误:绑定(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的常量部分成为绑定(bind)属性-这样的覆盖根本不可能。可能是一个(历史性的猜测)一个历史性的问题:最初,该安装程序仅在Swing中可用(出于充分的理由)。在向awt的反向移植中,它突变为从未有过的bean属性。

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

    10-10 14:42