7

I was used to subclassing the window-classes in other programming environment, but in the java tutorials I usually see something like

JPanel p = new JPanel();
p.setLayout(new BoxLayout(p, BoxLayout.PAGE_AXIS));

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

So what are the conventions in Java regarding subclassing top-container classes?

Georg Schölly
  • 124,188
  • 49
  • 220
  • 267
  • 1
    This question is similar to should I use anonymous Classes or should I name them -> there is no right or wrong. – rurouni May 05 '11 at 09:25

5 Answers5

6

Use the same principle as you would for all java classes. If you are modifying or extending the behaviour or functionality, then by all means, extend JPanel or JFrame. The trick is to think carefully and decide if you really are adding anything. In most cases when I see people extending JFrame it is unnecessary and wrong;

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

Why bother extending JFrame? You haven't added anything! Composition is a much better option.

Extending JPanel is a little different. JPanel is a fairly abstract idea, its just a generic container for other components. IMHO it is valid to subclass JPanel to create a more concrete panel, and then use that in your application. It promotes OOP and encapsulation.

For example, say your GUI had 2 main display areas; one with some buttons/controls/inputs and another which displayed output (eg in a text area). It is perfectly acceptable to subclass JPanel to create a ControlPanel that contains the buttons/controls/inputs. This moves all the code into a nice neat module, cleaning up your class that contains and handles the main JFrame.

Qwerky
  • 18,217
  • 6
  • 44
  • 80
  • Often, when people have a main application class with data attributes and business logic etc, you see them extending JFrame purely in order to give their app a GUI. IMO this is wrong, because it's not an *is-a*, it's a *has-a*! As you said, composition the correct approach. However, if you do *need* to extend JFrame/JPanel to **add some UI-related functionality to it**, don't use this an excuse to put everything in one class. You should give your application class an instance of your extended JFrame, and not start storing business logic/data in what should be a purely UI class. Just my $0.02. – Cam Jackson Sep 05 '11 at 00:38
3

There is no rule for this, it depends how you think about your Object. You may have a JPanel which has a specific layout and bahavior, so its e.g. a VideoViewerPanel. But even this VideoViewerPanel may contain a JPanel which is only there to arrange some Buttons so you do not expicitly name it and just use it as JPanel.

rurouni
  • 2,315
  • 1
  • 19
  • 27
2

I think this is related to the Liskov substitution principle, you should look into it.

Liskov substitution principle

Liskov substitution principle: Applied example

G-Man
  • 1,321
  • 8
  • 15
2

A well-known and good practice is to avoid subclassing top-level containers (JFrame, JDialog, JInternalFrame).

Regarding JPanel, several practices are in use:

  • subclass it for every view (then add all components inside the subclass constructor)
  • create a ViewBuilder (for each kind of view) that dynamically adds components to a "standard" JPanel

I generally use the first option, which seems more logical to me, but I also sometimes use the second way, with some level of adaptation: my view builder actually creates and stores (as fields) all components but adds them to an existing panel (passed as an argument).

For example, I use that in order to reuse sets of components: e.g. I have an AddressView class that works like that and I add it twice to a ContactView that subclasses JPanel, once for home address, once for office address.

One may say that I could also subclass JPanel for AddressView and then add 2 instances to my ContactView panel. The reason I don't do that is because Swing LayoutManagers don't support alignment of components across different panels, thus the resulting ContactView panel is not visually pleasing in this case.

jfpoilpret
  • 10,449
  • 2
  • 28
  • 32
0

My general rule of thumb: Before using inheritance, consider if composition makes more sense.

Reason: Subclassing usually means more complexity and connectedness, i.e. harder to change, maintain, and scale without making mistakes.

A much more complete and concrete answer from Tim Boudreau of Sun:

Common problems to the use of inheritance as I see it are:

  • Innocent acts can have unexpected results - The classic example of this is calls to overridable methods from the superclass constructor, before the subclasses instance fields have been initialized. In a perfect world, nobody would ever do that. This is not a perfect world.
  • It offers perverse temptations for subclassers to make assumptions about order of method calls and such - such assumptions tend not to be stable if the superclass may evolve over time. See also my toaster and coffee pot analogy.
  • Classes get heavier - you don't necessarily know what work your superclass is doing in its constructor, or how much memory it's going to use. So constructing some innocent would-be lightweight object can be far more expensive than you think, and this may change over time if the superclass evolves
  • It encourages an explosion of subclasses. Classloading costs time, more classes costs memory. This may be a non-issue until you're dealing with an app on the scale of NetBeans, but there, we had real issues with, for example, menus being slow because the first display of a menu triggered massive class loading. We fixed this by moving to more declarative syntax and other techniques, but that cost time to fix as well.
  • It makes it harder to change things later - if you've made a class public, swapping the superclass is going to break subclasses - it's a choice which, once you've made the code public, you're married to. So if you're not altering the real functionality to your superclass, you get much more freedom to change things later if you use, rather than extend the thing you need. Take, for example, subclassing JPanel - this is usually wrong; and if the subclass is public somewhere, you never get a chance to revisit that decision. If it's accessed as JComponent getThePanel() , you can still do it (hint: expose models for the components within as your API).
  • Object hierarchies don't scale (or making them scale later is much harder than planning ahead) - this is the classic "too many layers" problem. I'll go into this below, and how the AskTheOracle pattern can solve it (though it may offend OOP purists).

...

My take on what to do, if you do allow for inheritance, which you may take with a grain of salt is:

  • Expose no fields, ever, except constants
  • Methods shall be either abstract or final
  • Call no methods from the superclass constructor

...

all of this applies less to small projects than large ones, and less to private classes than public ones

Peter Tseng
  • 13,613
  • 4
  • 67
  • 57