nac*_*okk 10 java swing liskov-substitution-principle jcomponent
我总是在这个覆盖的站点中看到建议,getPreferredSize() 而不是setPreferredSize() 像以前的这些线程中所示那样使用.
看这个例子:
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());
}
}
Run Code Online (Sandbox Code Playgroud)
setPreferredSize()
- 设置此组件的首选大小.
getPreferredSize()
- 如果preferredSize已设置为非null值,则返回它.如果UI委托的getPreferredSize方法返回非null值,则返回该值; 否则遵从组件的布局管理器.
所以这样做显然打破了Liskov替代原则.
prefferedSize是一个绑定属性,所以当你设置它时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());
}
}
Run Code Online (Sandbox Code Playgroud)
现在我们看到我们得到了相同的结果,但听众会得到真实值的通知,而且我们不会破坏LSP原因setPreferredSize状态Sets the preferred size of this component.而不是如何.
一般来说,这个问题没有简单(或正确)的答案.
最重要的是getPreferredSize打破Liskov替换原则吗?是(基于可用的文档).
但是大部分对象扩展都没有?什么是改变一个方法的行为的点,如果它有严格遵守原来实行的期望(是的,有很好的例子时,你应该这样做,像hashcode和equals等在那里的线是灰色的)?
在这种情况下,问题似乎从不恰当的使用setXxxSize和实际上这些方法的事实延伸出来public.他们为什么公开?我不知道,因为它们是导致更多问题的原因,而不仅仅是API的任何其他部分(包括KeyListener).
由于对象所有权/上下文之外的getPreferredSize调用不同,所以优先覆盖是因为对象携带了更改setPreferredSize
因为getXxxSize假设要给布局管理器提供大小调整提示,实际上似乎没有任何合理的理由来实际拥有这些setXxxSize方法,public因为恕我直言,开发人员不应该弄乱它们 - 需要一个组件来提供最好的根据自己的内部要求估算所需的规模.
getXxxSize以这种方式覆盖的原因还在于防止其他人改变您指定的值,这可能是由于特定原因造成的.
一方面,正如您所建议的那样,我们对API有所期待,但另一方面,当您不希望用户更改值时,我们有时会想要控制大小和很多次.
我个人的感觉是尽可能地忽略setXxxSize(或将其视为protected).覆盖的原因之一getXxxSize是阻止人们改变大小,但同样,你可以覆盖setXxxSize并抛出一个不支持的异常.
如果你要记录忽视setXxxSizeLiskov替代原则的决定吗?可能,因为组件仍然可以像它的父母那样行事.
我的一般直觉是了解利斯科夫替代原则试图做什么,知道何时应该使用它以及何时不应该使用它.不能满足每种情况的明确规则,特别是当您考虑设计本身错误的情况时.
根据你的例子,你不应该覆盖getXxxSize或者根本不应该覆盖构造函数,因为这将保持当前的API契约,但也会踩到从构造函数setXxxSize调用可覆盖setXxxSize方法的脚趾......
所以无论你看到什么,你都会踩到别人的脚趾......
缺一切.如果它对您很重要(维护Liskov替换原则),则应setXxxSize在您自己的组件上下文中使用.这样做的问题在于,不可能阻止某人用自己的价值观来消除你的设计决策,正如我在评论中所说,当人们在没有真正了解他们正在做的事情的情况下这样做时,这只会让每个人都成为噩梦.
不要滥用setPreferredSize,只能在对象实例的上下文中使用它并拒绝从外部调用它...恕我直言
这个有趣问题的几个方面(Mad已经提到了备用我的同事 - 开发人员)
我们是否在覆盖getXXSize()时也违反了LSP(与setXXSize()相比)?
如果我们正确地执行它,那就不是:-)第一个权限是属性的API文档,最好从它的来源,即组件:
将此组件的首选大小设置为常量值.对getPreferredSize的后续调用将始终返回此值.
这是一个有约束力的契约,所以我们实现getter它必须尊重常量值,如果设置:
@Override
public Dimension getPreferredSize() {
// comply to contract if set
if(isPreferredSizeSet())
return super.getPreferredSize();
// do whatever we want
return new Dimension(dim);
}
Run Code Online (Sandbox Code Playgroud)
XXSize是一个绑定属性 - 是吗?
在JComponent的祖先中只有间接证据:实际上,Component会在setter中触发PropertyChangeEvent.JComponent本身似乎记录了这个事实(由我加粗):
@beaninfo preferred:true bound:true description:组件的首选大小.
哪个是......明显错误:作为绑定属性意味着只要值发生变化就需要通知侦听器,即以下(伪测试)必须通过:
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);
Run Code Online (Sandbox Code Playgroud)
......但失败了.由于某种原因(不知道为什么可能认为合适),他们希望xxSize 的常量部分成为绑定属性 - 这样的叠加是根本不可能的.本来可以(疯狂地猜测)一个历史性问题:最初,只有Swing才能使用setter(有充分的理由).在它的backport中,它变成了一个从未有过的bean属性.
| 归档时间: |
|
| 查看次数: |
924 次 |
| 最近记录: |