我应该是否继承JFrame / JPanel?

时间:2011-05-05 09:16:12

标签: java swing

我习惯于在其他编程环境中对窗口类进行子类化,但在java教程中我经常会看到类似

的内容。
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.PAGE_AXIS));

p.add(aComponent);
p.add(anotherComponent);

那么Java中有关子类化顶级容器类的约定是什么?

5 个答案:

答案 0 :(得分:6)

使用与所有java类相同的原则。如果您正在修改或扩展行为或功能,请务必延伸JPanelJFrame。诀窍是仔细思考并确定你是否真的在添加任何东西。在大多数案例中,当我看到人们延长JFrame时,这是不必要和错误的;

public class MyFrame extends JFrame {
  public static void main(String[] args) {
    new MyFrame().setVisible(true);
  }
}

为什么要延长JFrame?你没有添加任何东西!组合是一个更好的选择。

扩展JPanel略有不同。 JPanel是一个相当抽象的想法,它只是其他组件的通用容器。恕我直言,将JPanel子类化为创建更具体的面板是有效的,然后在您的应用程序中使用它。它促进了OOP和封装。

例如,假设您的GUI有2个主要显示区域;一个带有一些按钮/控制/输入,另一个带有显示输出(例如在文本区域中)。子类JPanel创建包含按钮/控件/输入的ControlPanel是完全可以接受的。这会将所有代码移动到一个漂亮的整齐模块中,清理包含并处理主JFrame的类。

答案 1 :(得分:3)

没有这方面的规则,这取决于你如何看待你的对象。您可能有一个具有特定布局和行为的JPanel,因此它可以是一个VideoViewerPanel。但即使是这个VideoViewerPanel也可能包含一个JPanel,它只是为了安排一些按钮,所以你没有明确地命名它,只是将它用作JPanel。

答案 2 :(得分:2)

我认为这与Liskov替代原则有关, 你应该调查一下。

Liskov substitution principle

Liskov substitution principle: Applied example

答案 3 :(得分:1)

一个众所周知的良好做法是避免继承顶级容器(JFrameJDialogJInternalFrame)。

关于JPanel,正在使用几种做法:

  • 为每个视图创建子类(然后添加 子类内的所有组件 构造函数)
  • 创建 ViewBuilder (适用于各种类型 动态添加的视图) 组件为“标准”JPanel

我通常使用第一个选项,这对我来说似乎更合乎逻辑,但我有时也会使用第二种方式,适应水平:我的视图构建器实际上创建并存储(作为字段)所有组件但是将它们添加到现有面板(作为参数传递)。

例如,我使用它来重用组件集:例如我有一个类似的AddressView类,我将它添加到ContactView的子类JPanel,一次添加到家庭地址,一次添加到办公地址

可以说我也可以为JPanel创建AddressView的子类,然后将2个实例添加到ContactView面板中。我不这样做的原因是因为Swing LayoutManager不支持跨不同面板对齐组件,因此在这种情况下生成的ContactView面板在视觉上并不令人满意。

答案 4 :(得分:1)

我的一般经验法则:在使用继承之前,请考虑合成是否更有意义。

原因:子类化通常意味着更多的复杂性和连通性,即更难以改变,维护和扩展而不会出错。

更完整,更具体的answer from Tim Boudreau太阳:

  

我认为使用继承的常见问题是:

     
      
  • 无辜的行为会产生意想不到的结果 - 这个经典的例子是从超类中调用可覆盖的方法   构造函数,在子类实例字段之前   初始化。在一个完美的世界里,没有人会这样做。这是   不是一个完美的世界。
  •   
  • 它为子类提供了不正确的诱惑,以便对方法调用的顺序做出假设等等 - 这种假设往往不会   如果超类可能会随着时间的推移而变得稳定。另请参阅my toaster and coffee pot analogy
  •   
  • 类变得越来越重 - 你不一定知道你的超类在它的构造函数中做了什么工作,或者它的内存是多少   使用。因此,构建一些无辜的轻量级对象可以   比你想象的要贵得多,如果这种情况可能会随着时间而改变   超类演变
  •   
  • 它鼓励子类爆炸。类加载成本时间,更多类成本内存。这可能是一个非问题,直到你   处理NetBeans规模的应用程序,但在那里,我们有真实的   例如,由于第一个显示器,菜单很慢   一个菜单触发了大量的类加载。我们通过迁移来解决这个问题   更多的声明性语法和其他技术,但这需要花费时间   也可以修复。
  •   
  • 这使得以后更改内容变得更加困难 - 如果你公开了一个类,那么交换超类会打破子类 -   这是一个选择,一旦你公开了代码,你就结婚了   至。所以,如果你没有改变你的真实功能   如果你超级,那么你以后可以更自由地改变事物   使用,而不是扩展你需要的东西。举个例子,   子类化JPanel - 这通常是错误的;如果子类是   在某个地方公开,你永远不会有机会重新审视这个决定。如果   它作为JComponent getThePanel()访问,你仍然可以这样做(提示:   公开API中的组件模型。
  •   
  • 对象层次结构不能扩展(或者使它们扩展比以后规划要困难得多) - 这是经典的“太多层次”   问题。我将在下面讨论,以及AskTheOracle模式如何   解决它(虽然它可能冒犯OOP纯粹主义者)。
  •   
     

...

     

如果你允许继承,我可以做什么   拿一粒盐是:

     
      
  • 除了常量
  • 之外,不要公开任何字段   
  • 方法应为抽象或最终
  •   
  • 从超类构造函数中调用no方法
  •   
     

...

     

所有这些对小型项目的应用较少,而不是大型项目   私人课程而非公共课程