Forums Register Login

composition vs inheritance

+Pie Number of slices to send: Send
i doubt this is the first thread about this, but what does it hurt to talk about it some more? i think most people will say choose composition over inheritance, but perhaps they are just parroting what others say. i have done it both ways. when i transferred to university we had to use a MVC framework. i didn't have a problem, in fact i kind of liked it. the View class didn't extend JFrame it had one. and the Controller handled the events. it seemed to make sense in that context, but i remain unconvinced. maybe it is because the projects i write are small. if i have a single class with only around 100 lines of code, why not extend JFrame? if i didn't and i wanted to set the size from main() i would have to write a method to do it. and if i only have one event, what is the point of writing another class to handle it? i admit i have had programs with so many events that actionPerformed() started to look ugly with all the else if"s. but in general i don't see what people say is "wrong" with inheritance. i would call it a feature not a bug.
1
+Pie Number of slices to send: Send
I think you are right when you say "perhaps they are just parroting what others say". I already saw many people saying to use composition rather than inheritance, but without a good reason. We only have to be careful when using inheritance because, as Kent Beck would say, inheritance is a card we can only play once.

The thing is, it is 100% correct to use inheritance if the subclass is a special type of the class being extended. If we look at the Swing framework, we'll see so much inheritance!!! Some people may have a hard time figuring when to use "is-a" and "has-a", because, after 7 years working with Java, I can tell that object orientation is not an easy thing. And for the ActionListeners, I always use one ActionLister for each button. This way, each class is able to stick to the SRP (or Single Responsibility Principle).
+Pie Number of slices to send: Send
 

I always use one ActionLister for each button.


i am beginning to go along with that idea. if nothing else it improves readability. strange the MVC framework we used at university had one listener for everything.

object orientation is not an easy thing.


amen to that! it took me forever before i even began to understand(i was used to procedural and failed to see what the big deal was)
+Pie Number of slices to send: Send
 

Randall Twede wrote:i think most people will say choose composition over inheritance, but perhaps they are just parroting what others say. i have done it both ways.


Actually, I like the way Josh Bloch puts it: "Design and document for inheritence; or else prohibit it".

For one thing, it highlights the fact that every aspect of inheritance needs to be documented (specifically: self-use, and the effects of overriding any overridable method); and secondly, it points you towards using final classes. In fact, I make it a point now to add final to every class and method I write, because you can always remove it later on if it's too restrictive. It's almost impossible to add it later though, when you realize it should have been there all the time. Indeed, I wish Eclipse would make it an option for auto-generated methods.

The great thing about composition is that you can stick final anywhere you like.

Other than that, I agree completely with Roberto.

Winston
+Pie Number of slices to send: Send
i finally heard a fairly compelling argument for not having a JFrame be a listener. i make my JFrame public and my event handling code is public too. in fact for ActionListener , actionPerformed() is declared public so i MUST make it public too. seems like a good reason to use inner classes to be the listeners.
+Pie Number of slices to send: Send
I would see it this way: The classes should be designed keeping in mind the Single Responsibility Principle and the hierarchy should be designed such that it doesn't violate the Liskov Substitution Principle or the Open Closed principle .

We shouldn't be using inheritance just because we want to make use of a functionality of other classes- I have seen this being done and inheritance also puts a restriction on number of classes one can inherit. Its more of avoiding abuse of Inheritance.

If all my buttons/components have different behavior then I would may be go with anonymous inner classes for defining the ActionListener.
+Pie Number of slices to send: Send
i appreciate the replies and especially the links.
i changed a very simple program to use an inner class as an action listener. the experience changed my mind. for simple programs i still think it is better to just extend JFrame and implement ActionListener.
i will post both codes and you tell me which is better.
original code:

the new code. it works but i dont like it. for one thing i had to write a constructor for the inner class that was passed a reference to the outer class in order for the dialogs to work properly.
i have done similarly in other programs, but in this case it bothers me.

even worse, both classes share the one outer class member variable(the JLabel).
of course we could correct that by passing it in the constructor as well(an even worse idea IMO).

the inner class also calls methods of the outer class(not sure this such a good idea either)

so i think for this program the original code is better.
i mean, who is going to instantiate my class in one they wrote and call my actionPerformed()?
sometimes i think we worry too much.
i admit in a larger, more complicated program these things might matter.
+Pie Number of slices to send: Send
 

Mohamed Sanaulla wrote:...and the hierarchy should be designed such that it doesn't violate the Liskov Substitution Principle...


Further to Mohamed's point, you might be interested in this Is a Square a Rectangle? page.

Winston
+Pie Number of slices to send: Send
i'm beginning to see the light. why am i extending JFrame when i don't override any of it's methods?
i can do this:
public class ImageViewer implements ActionListener
private JFrame frame = new JFrame();

and move the method calls from main() to the constructor where they probably belong anyway.

or i could do this:
public class ImageViewer

and have the inner class. because the outer class is no longer the JFrame i won't have to write a constructor for the inner class(and pass "this" to it).
+Pie Number of slices to send: Send
You could think in this way: ImageViewer is a JFrame or ImageViewer uses a JFrame? I think the second option sounds suitable?
I would prefer a different class for handing the actions- it increases the code clarity to a great extent. When you separate the tasks involved, it becomes easier to think- because you can now think on the basis of task you would want to finish. A concern here would be that when you have a separate class for ActionListener then there should be some way to get hold of the object on which you would want to perform some action- this again can be accomplished by composing the object within the ActionListener.

Or if the actionPerformed is simple and using a anonymous inner class doesn't degrade the code clarity, I would go with it.

I am not sure if these would make sense for a smaller codebase, but definitely will be more concerning when the codebase becomes larger.
+Pie Number of slices to send: Send
i think my last idea is best. a plain old java object and a named inner class that doesn't need a written constructor now
+Pie Number of slices to send: Send
Take a look at this code and tell me what you think, Randall.
+Pie Number of slices to send: Send
i like it. for one thing moving JFileChooser out of actionPerformed(). i have been working on it but i couldnt get the setSize() and center() and setDefault and all that to work in the constructor.
i guess that is what this is for:
public static void main(String... args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ImageViewer();
}
});
+Pie Number of slices to send: Send
i like the displayImage() method also. im still having a problem in my constructor. i have to look at your code some more to figure out what i'm doing wrong
+Pie Number of slices to send: Send
Yep. All code dealing with Swing components should be run on the event dispatch thread. invokeLater() takes care of this.

Note also that there is a strong separation between the actions and the viewer here. I made the actions private fields, only because I think the code is a bit more readable that way (especially the constructor); they can very easily be put in their own source files as well (the file chooser would have to move with the open action though).

What I always do when I make GUIs is provide all the methods that make the GUI usable programmatically as well as through user interaction. Here, you can display an image programmatically very easily. All the listener really does is ask the user for input and then call the method. This makes it very easy to separate controllers from views.
+Pie Number of slices to send: Send
agreed

i almost have it working now. i had one line in the constructor
setVisible(true);
where i forgot to say
window.setVisible(true);

yeah i am making the action listener a private variable... no wait...i made it a local variable in the constructor

got it working, but still do a lot in actionPerformed()

will look at your code some more later and maybe seperate things.

one last problem fixed. it didn't turn up until i noticed i was still extending JFrame. i had to change
window.setDefaultCloseOperation(EXIT_ON_CLOSE);
to
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

so i like this better than either of the original ones:

+Pie Number of slices to send: Send
Champion, how about moving the OpenListener class out of the ImageViewer class? I myself avoid inner classes as much as possible... actually, I never use them!

Also, I would keep the ImageViewer class extending JFrame. I think it makes sense, since you want it to be a special type of JFrame.
+Pie Number of slices to send: Send
i am also a little leery of using inner classes. however in this case i think it is good for 3 reasons.
first, the code is not reusable. it only makes sense in this program.
second, the code doesn't do much and it will do even less if i make it more like what Stephan wrote.
third, if i make it a top level class, i might once again have to write a constructor and pass a reference to "this".

and i now don't think it actually should be a sub-class of JFrame because i don't override any methods.
+Pie Number of slices to send: Send
Ok, champ. I'd still prefer to have a separate class. But I guess this is just a matter of taste.

and i now don't think it actually should be a sub-class of JFrame because i don't override any methods.



Well champ, it's not because you aren't overriding a method that you shouldn't extend another class. The thing is, your ImageViewer represents a window. In other words, the ImageViewer is-a JFrame. This goes back to the things we were talking about in the beginning of this thread. Thinking of the ImageViewer as a JFrame will help you maintain it in the future.

This is just my opinion.
+Pie Number of slices to send: Send
 

The thing is, your ImageViewer represents a window.


yes, and this bothers me a little, but i am still thinking if i don't override or overload a method of a class, i shouldn't extend it.

this has been a good learning experience for me. sometime a simple example will not hide the bigger concepts.

thanks again to all of you especially Stephan

and if you compile and run the code i hope you enjoy. i kind of like it (it is so simple).
There are no more "hours", it's centi-days. They say it's better, but this tiny ad says it's stupid:
a bit of art, as a gift, the permaculture playing cards
https://gardener-gift.com


reply
reply
This thread has been viewed 1866 times.
Similar Threads
MyGUI extends JFrame - good or bad?
Thread vs Runnable
Inheritence or Abstract class
Multiple inheritance
when extend a class
[joke] racy parrot
@#%&*! Parrot!
MVC in swing
static import of ActionCommands.
More...

All times above are in ranch (not your local) time.
The current ranch time is
Mar 28, 2024 02:50:22.