我总是在这个网站上看到覆盖 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()
- 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/