重写getPreferredSize()会破坏LSP [英] Overriding getPreferredSize() breaks LSP

查看:177
本文介绍了重写getPreferredSize()会破坏LSP的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I always see advices in this site of overriding getPreferredSize() instead of using setPreferredSize() as shown in these previous threads for example.


  1. 使用重写getPreferredSize()而不是使用setPreferredSize()用于固定大小的组件

  2. 我应该避免使用set(Preferred | Maximum | Minimum )Java Swing中的大小方法?

  3. 重写setPreferredSize ()和getPreferredSize()

  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 ()



  • 设置此组件的首选大小。

getPreferredSize()



  • 如果preferredSize已设置为非空值,则返回。如果UI委托的getPreferredSize方法返回非null
    值,则返回该值;否则按照组件的布局
    经理。

  • 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替代原则

prefferedSize 是一个绑定属性,所以当你设置它时,会执行 firePropertyChange 。所以我的问题是当你覆盖 getPrefferedSize()你是否还需要覆盖 setPreferredSize(..)

prefferedSize is a bound property so when you set it a firePropertyChange is executed. So my question is when you override getPrefferedSize() don't you need to override setPreferredSize(..) too?

示例:

 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 states 设置此组件的首选大小。但不是如何。

Now we see that we get identical results but listeners will get notified with real values and besides we don't break LSP cause setPreferredSize states Sets the preferred size of this component. but not how.

推荐答案

这个有趣的问题的几个方面(Mad已经提到了我的同伴 - 开发人员)

Several aspects to this interesting question (Mad already mentioned the spare-my-fellow-developer)

我们是否在覆盖getXXSize()时违反了LSP(与setXXSize()相比)?

如果我们正确地做到了这一点:-)第一个权威是属性的API文档,最好来自它的来源,即组件:

Not if we do it correctly :-) First authority is the API doc of the property, best from its origin, that is Component:


将此组件的首选大小设置为常量值。对getPreferredSize的后续调用将始终返回此值。

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

这是一个绑定合同,所以我们实现getter它必须尊重设置为常量值:

This is a binding contract, so however we implement the getter it has to respect the constant value if set:

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

XXSize是绑定属性 - 是吗?

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

In JComponent's ancestry there is circumstantial evidence only: actually, Component fires a PropertyChangeEvent in the setter. JComponent itself seems to document the fact (bolding by me):


@beaninfo
首选:true
bound:true
description:组件的首选大小。

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

哪个是......平原错误:作为绑定属性意味着只要值发生变化就需要通知侦听器,即以下(伪测试)必须通过:

Which is ... plain wrong: being a bound property implies that listeners need to be notified whenever the value changes, that is the following (pseudo-test) must pass:

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的常量部分是一个绑定的属性 - 这样的叠加是根本不可能的。本来可以(疯狂地猜测)一个历史问题:最初,setter只在Swing中可用(有充分的理由)。在它的后端到awt它变成了一个bean从未有过的财产。

... but fails. For some reason (no idea why that might have deemed appropriate) they wanted the constant part of xxSize to be a bound property - such overlays are simply not possible. Could have been (wildly guessing, of course) a historic issue: initially, the setter was available in Swing only (for good reasons). In its backport to awt it mutated into a bean property that it never was.

这篇关于重写getPreferredSize()会破坏LSP的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆