Java Forum / General / December 2007
Is this code "proper" use of extend?
CJ - 29 Nov 2007 17:24 GMT Thanks in advance for your responses.
I am relatively new to OOP and though I have muscled my way through Java, I am still trying to correctly understand the concepts of OO and how then are modeled into Java.
I am a thirty year procedural language developer, c and assembler, to this (recent) technology called Object Oriented whatever is somewhat alien to my experiences. I think I grasp the basic concepts of OO, that being describing concrete "objects" as a series of refinements to abstract "conceptual objects." (Please don't flame me if that statement is incorrect, I am seeking to increase my understanding.)
The following Java 1.5 code I believe demonstrates the statement above. I needed Vector container that would notify() all active Objects it contains. My thinking was to simply extend Vector adding the functionality I wanted.
However, a co-worker is rather irate at me for "doing such a silly thing," preferring instead to Instantiate a Vector object with SignaledVector, and implement the entire Vector contract method by method. That just sounds contrary to principles OO.
Your thoughts?
import java.util.Collection; import java.util.Vector;
public class SignaledVector<E> extends Vector<E> { public SignaledVector() { super(); } // public SignaledVector()
public SignaledVector(int initialCapacity) { super(initialCapacity); } // public SignaledVector(int initialCapacity)
public SignaledVector(int initialCapacity,int capacityIncrement) { super(initialCapacity,capacityIncrement); } // public SignaledVector(int initialCapacity,int capacityIncrement)
public SignaledVector(Collection<? extends E> c) { super(c); } // public SignaledVector(Collection<? extends E> c)
//public synchronized boolean add(E e) { return(super.add(e)); }
/** * Sends a signal to the object that has posted a {@code this.wait()} * * @param index the index in the element to signal * @return the component at the specified index * @throws ArrayIndexOutOfBoundsException * */ public E signal(int index) throws ArrayIndexOutOfBoundsException { E element = get(index); synchronized(element) { element.notify(); } return(element); } // public final void signal<E>(int index)
/** * Sends a signal to the object that has posted a {@code this.wait()} * This method sends a {@code synchronized} signal to all elements * contained in the {@code SignaledVector} * * @throws ArrayIndexOutOfBoundsException * */ public synchronized void signalAll() throws ArrayIndexOutOfBoundsException, NullPointerException { java.util.Enumeration<E> threads = elements();
while(threads.hasMoreElements()) { E element = threads.nextElement(); if (null == element) continue; synchronized(element) { element.notify(); } } // while(threads.hasMoreElements()) } // public final void signalAll() } // public class SignaledVector<E> extends Vector<E>
cj
Joe Attardi - 29 Nov 2007 17:37 GMT > I am relatively new to OOP and though I have muscled my way through > Java, I am still trying to correctly understand the concepts of OO and > how then are modeled into Java. It's a tough shift in thinking going from procedural to OO, for sure. It's a fun journey though!
> However, a co-worker is rather irate at me for "doing such a silly > thing," preferring instead to Instantiate a Vector object with > SignaledVector, and implement the entire Vector contract method by > method. That just sounds contrary to principles OO. That is what's known as composition. Sometimes it certainly is a better fit than inheritance, but in the case of your SignaledVector class you are making a more specialized version of Vector. Your coworker is wrong to chastise you for your design choice here, IMHO.
If the intention of SignaledVector is to be a special type of Vector, which performs all the normal collection related functions of a Vector, with some extra behavior tacked on (which is how it looks to me), then you are on the right track!
CJ - 29 Nov 2007 18:36 GMT > > I am relatively new to OOP and though I have muscled my way through > > Java, I am still trying to correctly understand the concepts of OO and [quoted text clipped - 17 lines] > with some extra behavior tacked on (which is how it looks to me), then > you are on the right track! Joe, that is exactly my thoughts, creating a specialized "is-a" Vector. Thanks.
Jason Cavett - 29 Nov 2007 19:05 GMT > > > I am relatively new to OOP and though I have muscled my way through > > > Java, I am still trying to correctly understand the concepts of OO and [quoted text clipped - 21 lines] > Vector. > Thanks. BTW, CJ, you may want to consider using an ArrayList as opposed to a Vector. If I remember correctly, Vectors are unofficially considered deprecated. If you want the synchronization of a Vector, look into the Collections.synchronized* methods.
List<E> list = Collections.synchronizedList(new ArrayList<E>());
Lew - 30 Nov 2007 01:39 GMT > BTW, CJ, you may want to consider using an ArrayList as opposed to a > Vector. If I remember correctly, Vectors are unofficially considered > deprecated. If you want the synchronization of a Vector, look into > the Collections.synchronized* methods. > > List<E> list = Collections.synchronizedList(new ArrayList<E>()); Vector is "deprecated" because it contains legacy non-Collection methods, and because it has all synchronized methods, forcing you to synchronize whether you want to or not.
With Java 5, and even more with Java 6, the price of extra synchronization is much lower, pretty much gone if you don't share the object between threads. However, ArrayList is the canonical "cleaner" Collection class to use in preference to Vector. (The other List implementations are also available if you need their particular characteristics.)
 Signature Lew
Arne Vajhøj - 02 Dec 2007 02:50 GMT > Vector is "deprecated" because it contains legacy non-Collection > methods, and because it has all synchronized methods, forcing you to > synchronize whether you want to or not. Vector is not deprecated.
ArrayList should be preferred over Vector.
But the term deprecated has a specific meaning in Java and I think it confuses if it is used in other meanings.
Arne
Lew - 02 Dec 2007 02:57 GMT >> Vector is "deprecated" because it contains legacy non-Collection >> methods, and because it has all synchronized methods, forcing you to [quoted text clipped - 6 lines] > But the term deprecated has a specific meaning in Java and > I think it confuses if it is used in other meanings. I agree, which is why I put the term in quotes when citing someone else's use of the term.
However, "deprecated" also has a specific meaning in English, and that meaning fits the usage quite nicely with respect to java.util.Vector (and Hashtable).
I'm not so sure we can reject normal English outright here.
 Signature Lew
Arne Vajhøj - 02 Dec 2007 03:09 GMT >>> Vector is "deprecated" because it contains legacy non-Collection >>> methods, and because it has all synchronized methods, forcing you to [quoted text clipped - 15 lines] > > I'm not so sure we can reject normal English outright here. In this case I think we should.
Vector is "deprecated" but it is not deprecated - does not seem to me to be a clear message to send.
:-) Arne
Daniel Pitts - 02 Dec 2007 18:09 GMT >>>> Vector is "deprecated" because it contains legacy non-Collection >>>> methods, and because it has all synchronized methods, forcing you to [quoted text clipped - 24 lines] > > Arne Especially since proper English dictates that the non-english meaning should be quoted.
"Vector is deprecated but it is not 'deprecated'." I would (and will) specifically say... Vector *should* be marked deprecated. It is out of date and no longer standard. Along with Hashtable.
 Signature Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
Joshua Cranmer - 03 Dec 2007 00:44 GMT > Vector *should* be marked deprecated. It is out of date and no longer > standard. Along with Hashtable. From what I can tell, the only reason Vector and Hashtable are not deprecated are that doing so would require too many API changes for pre-Collections code, and would horribly break backwards compatibility. (See JTree for example)
 Signature Beware of bugs in the above code; I have only proved it correct, not tried it. -- Donald E. Knuth
John W. Kennedy - 03 Dec 2007 01:47 GMT > Vector *should* be marked deprecated. Not until every existing API demanding Vector and/or Enumerator (such as SequenceInputStream) has a replacement based on List or Interator.
 Signature John W. Kennedy "Sweet, was Christ crucified to create this chat?" -- Charles Williams. "Judgement at Chelmsford"
Daniel Pitts - 03 Dec 2007 06:07 GMT >> Vector *should* be marked deprecated. > > Not until every existing API demanding Vector and/or Enumerator (such as > SequenceInputStream) has a replacement based on List or Interator. Actually, the point of deprecation is to allow those API's to be updated over time because of the knowledge that Vector and Enumerator are going away soon.
Deprecation is a label saying "Don't use this."
 Signature Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
John W. Kennedy - 03 Dec 2007 19:09 GMT >>> Vector *should* be marked deprecated. >> [quoted text clipped - 6 lines] > > Deprecation is a label saying "Don't use this." Yes, but the Lords of Java should get /their/ APIs straight, first, at least in the basic packages like java.io.*.
(Of course, the open-source transformation puts a new spin on this.)
 Signature John W. Kennedy "The grand art mastered the thudding hammer of Thor And the heart of our lord Taliessin determined the war." -- Charles Williams. "Mount Badon"
John W. Kennedy - 03 Dec 2007 01:43 GMT >>> Vector is "deprecated" because it contains legacy non-Collection >>> methods, and because it has all synchronized methods, forcing you to [quoted text clipped - 11 lines] > > However, "deprecated" also has a specific meaning in English, Yes, it does. "Deprecate" means to pray that God will prevent something from happening, from Latin "de" ("from") + "precare" ("pray").
Unfortunately, somebody about 75 years ago got the notion it was a high-falutin' way to pronounce "depreciate", "to lower the value of something".
 Signature John W. Kennedy Read the remains of Shakespeare's lost play, now annotated! http://pws.prserv.net/jwkennedy/Double%20Falshood/index.html
Lew - 03 Dec 2007 04:11 GMT Lew wrote:
>> However, "deprecated" also has a specific meaning in English,
> Yes, it does. "Deprecate" means to pray that God will prevent something > from happening, from Latin "de" ("from") + "precare" ("pray"). That definition is indeed listed as an archaic usage.
> Unfortunately, somebody about 75 years ago got the notion it was a > high-falutin' way to pronounce "depreciate", "to lower the value of > something". That definition does not appear. I find "to express disapproval of", "to play down / belittle, disparage", and "(computing) to discontinue".
<http://en.wiktionary.org/wiki/deprecate> <http://www.m-w.com/dictionary/deprecate>
 Signature Lew
John W. Kennedy - 03 Dec 2007 19:15 GMT > Lew wrote: >>> However, "deprecated" also has a specific meaning in English, > >> Yes, it does. "Deprecate" means to pray that God will prevent >> something from happening, from Latin "de" ("from") + "precare" ("pray").
> That definition is indeed listed as an archaic usage. "Archaic" is a grand word to use for something that was current a century ago and is still employed as a term of art.
>> Unfortunately, somebody about 75 years ago got the notion it was a >> high-falutin' way to pronounce "depreciate", "to lower the value of >> something".
> That definition does not appear. I find "to express disapproval of", ...which /is/ a form of lowering the value of something.
> "to play down / belittle, disparage", and "(computing) to discontinue". I grant that it is no more possible to repair the "deprecate"/"depreciate" mess than it is to repair "gentleman" or "awful", but it's still annoying.
 Signature John W. Kennedy "The first effect of not believing in God is to believe in anything...." -- Emile Cammaerts, "The Laughing Prophet"
Lew - 04 Dec 2007 01:30 GMT >>> Yes, it does. "Deprecate" means to pray that God will prevent >>> something from happening, from Latin "de" ("from") + "precare" ("pray"). Lew wrote:
>> That definition is indeed listed as an archaic usage.
> "Archaic" is a grand word to use for something that was current a > century ago and is still employed as a term of art. Take it up with the dictionary writers. I'm not the one who labeled it that.
 Signature Lew
Curt Welch - 30 Nov 2007 16:17 GMT > Thanks in advance for your responses. > [quoted text clipped - 20 lines] > > Your thoughts? I agree, it would be very silly to use a has-as relationship and duplicate the entire vector contract. If you want it to act like a vector, you did the right thing.
However, I'm not sure if you decision to create an object which acts like a vector is the right choice. You would have to tell us more about your application and what you were putting in that vector to allow us to suggest a different way to fracture your code to solve the problem.
Extending classes you don't have control over can be a risky business. What happens if the Java guys decide to add a "SignalAll" to the Vector class? (highly unlikely, but this is just an example). If they not only added that method in some future release but the Vector would call it's own signalAll method at times, your version of the method could end up breaking their code if it didn't happen to do just the right thing.
Using has-a relationships instead of is-a relationships in general is far safer.
You could have for example made a simple object which held the Vector and implemented the signal and signalAll methods on the vector as you did, as well as a getter to get the vector. To use the Vector methods, you just get the vector from the object and use the Vector methods on the vector instead of trying to make your object be a vector.
Though in OO terms, you did the right thing based on your description, as a practical mater of code maintenance, it might have been better to approach it differently.
On a larger scale, surely there is more you have to do with the objects in the vector than send these signals to them right? What puts the objects in the Vector and what takes them out? What type of objects are in the Vector? In general, when I find I need to do something to a Vector (like perform a method on every object in the Vector) it would be highly unlikely that I would end up approaching it like you did and extend the Vector class.
I'm sitting at my car dealer writing this message so let me make up an example based on that. Lets say I needed to represent the inventory of the dealer as a collection of cars. And one of the functions I needed to perform on the collection was to add up the wholesale price of all the calls to get a total value of the inventory. I could do this like you did by extending Vector to create a CarVector class and include in that class a totalWholesaleCost method which would call the wholeSaleCost method of each car in the Vector and return the sum. But I would not tend to do that.
Instead, I would create a CarDealer Object which had an inventory variable which was a Vector<Car>. And I would but the totalWholesaleCost method in the CarDealer object. It's likely the CarDealer object would have other instance variables as well such as the name of the dealer. There would be no need to create a special CarVector class to make any of this work just because there were things I needed to do to the objects in the Vector. So this is an example of the CarDealer class using the has-a relationship with the Vector instead of using the is-a relationship.
It's hard to tell whether the has-a relationship might work for you without understanding more about your application.
 Signature Curt Welch http://CurtWelch.Com/ curt@kcwc.com http://NewsReader.Com/
Lew - 01 Dec 2007 00:20 GMT > I agree, it would be very silly to use a has-as relationship and duplicate > the entire vector contract. If you want it to act like a vector, you did [quoted text clipped - 4 lines] > application and what you were putting in that vector to allow us to suggest > a different way to fracture your code to solve the problem. ...
> It's hard to tell whether the has-a relationship might work for you without > understanding more about your application. In his superb /Effective Java/, Joshua Bloch has a chapter (Item 14) devoted to the principle that one should "Favor composition over inheritance", with a detailed explanation as to why, and when the choice of inheritance is indicated.
Note that when Bloch says, "favor", he doesn't mean, "make a religion out of insisting on".
<http://www.amazon.com/Effective-Java-Programming-Language-Guide/dp/0321356683/>
 Signature Lew
Arne Vajhøj - 02 Dec 2007 02:44 GMT > In his superb /Effective Java/, Joshua Bloch has a chapter (Item 14) > devoted to the principle that one should "Favor composition over > inheritance", with a detailed explanation as to why, and when the choice > of inheritance is indicated. Yes, but his point does not apply for this case.
If I were to summarize his point with my words it would be: overriding some methods but not all methods makes the new class dependent of the implementation instead of just the interface of the old class because methods may call each other.
But in this case no existing methods are overridden so there are no problem.
Arne
Daniel Pitts - 02 Dec 2007 02:57 GMT >> In his superb /Effective Java/, Joshua Bloch has a chapter (Item 14) >> devoted to the principle that one should "Favor composition over [quoted text clipped - 12 lines] > > Arne If no existing method is overridden, then why have this class extend the other class at all? Why not do something like this: public class SpecialThing { final List list = new ArrayList();
public List getList() { return list; }
// Do special things here... }
This doesn't couple your SpecialThing to a particular inheritance structure, and clearly separates the List operations from the Special operations.
If SpecialThing should indeed be a "List with more functionality", then I really do prefer delegation over inheritance. Implement "List", and delegate to the backing list.
In reality, this is similar to what happens in inheritance anyway, it just hides what the "parent" class is from those who shouldn't care.
Hmm... Now that I've written this down, I need to spend some time to consider when its appropriate to use composition vs inheritance... I know there are really good reasons to use each for certain things, but I usually use intuition to tell me which...
One feature that I wish Java had would be to "list" methods for delegation. A special construct:
class Foo implements List { List myList; delegates<List.*>() {myList}; } Or some way to do easy grouping/pattern matching for names. Kind of like a compile-time proxy. It would help with AOP programming a bit.
 Signature Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
Arne Vajhøj - 02 Dec 2007 03:17 GMT >>> In his superb /Effective Java/, Joshua Bloch has a chapter (Item 14) >>> devoted to the principle that one should "Favor composition over [quoted text clipped - 13 lines] > If no existing method is overridden, then why have this class extend the > other class at all? It happen that people extend a class without overriding methods.
I am sure you have seen a couple of examples with JFrame.
> Why not do something like this: > public class SpecialThing { [quoted text clipped - 12 lines] > I really do prefer delegation over inheritance. Implement "List", and > delegate to the backing list. The original poster said that it was "with more functionality".
You can delegate. But it result in a lot more code. Sure your IDE can generate it, but it still clutter up the code base.
> In reality, this is similar to what happens in inheritance anyway, it > just hides what the "parent" class is from those who shouldn't care. It is what happen if no overridden methods. With overridden methods there are different semantics.
Runtime wise I don't know if the JIT can get rid of the extra delegation call.
Arne
Lew - 02 Dec 2007 03:00 GMT >> In his superb /Effective Java/, Joshua Bloch has a chapter (Item 14) >> devoted to the principle that one should "Favor composition over >> inheritance", with a detailed explanation as to why, and when the >> choice of inheritance is indicated. > > Yes, but his point does not apply for this case. Sure it does, at least the part as to "when the choice of inheritance is indicated."
> If I were to summarize his point with my words it would be: overriding > some methods but not all methods makes the new class dependent [quoted text clipped - 3 lines] > But in this case no existing methods are overridden so there > are no problem. So his point applies, on the other side.
The key here is that /Effective Java/ discusses why one would *favor* composition, and when it's appropriate to use inheritance anyway. You are not contradicting Mr. Bloch's points as far as I can tell.
Again, he does not espouse blindly applying such a rule when it doesn't make sense to.
 Signature Lew
Arne Vajhøj - 02 Dec 2007 03:27 GMT >>> In his superb /Effective Java/, Joshua Bloch has a chapter (Item 14) >>> devoted to the principle that one should "Favor composition over [quoted text clipped - 5 lines] > Sure it does, at least the part as to "when the choice of inheritance is > indicated." Programming is not black magic.
The fact that solution X applied to problem Y is bad does not imply that solution X is bad to problem Z.
>> If I were to summarize his point with my words it would be: overriding >> some methods but not all methods makes the new class dependent [quoted text clipped - 9 lines] > composition, and when it's appropriate to use inheritance anyway. You > are not contradicting Mr. Bloch's points as far as I can tell. No. His arguments are very valid.
They just don't apply for this case.
Arne
CJ - 03 Dec 2007 13:43 GMT > > Thanks in advance for your responses. > [quoted text clipped - 81 lines] > Curt Welch http://CurtWelch.Com/ > c...@kcwc.com http://NewsReader.Com/ To all,
Thank you all for your time spend responding. While the discussion moved a bit off topic, my understanding of OO has advanced -- forget the fact of whether my use of Vector as the example is the right move. I am more interested in the technique, as opposed to the "history" of Vector.
But Mr Welch noted something which disturbs me about the entire concept of OO. Specifically, Mr Welch wrote:
> Extending classes you don't have control over can be a risky business. > What happens if the Java guys decide to add a "SignalAll" to the Vector > class? (highly unlikely, but this is just an example). If they not only > added that method in some future release but the Vector would call it's own > signalAll method at times, your version of the method could end up breaking > their code if it didn't happen to do just the right thing. His statement is true for any base object that get extended, not just core object of the language. Any object can be "enhanced" -- for lack of a better word -- and the risk exists the "enhacement" conflicts with an object extending it. Does not his statement belie the "benefits" of OO, perhaps highlight a real danger in using OO?
cj
Joe Attardi - 03 Dec 2007 15:09 GMT > His statement is true for any base object that get extended, not just > core object of the language. Any object can be "enhanced" -- for lack > of a better word -- and the risk exists the "enhacement" conflicts > with an object extending it. Well, his statement covers "classes you don't have control over". That can mean a core object of the language or any third party API that you are using. He does raise an interesting point. There are some API classes meant to be extended - there are many abstract classes in the Java API that are obviously meant to be extended.
Extending other classes can be dangerous, per Curt Welch's point. But IMHO, it is your responsibility, as the author/maintainer of the subclass, to update your implementation from time to time when the class it extends changes.
Does that make any sense? I haven't had my coffee yet...
CJ - 03 Dec 2007 15:48 GMT > > His statement is true for any base object that get extended, not just > > core object of the language. Any object can be "enhanced" -- for lack [quoted text clipped - 13 lines] > > Does that make any sense? I haven't had my coffee yet... Joe, that makes sense. I think even I am getting off topic, this is after all a Java programming group, not one focused on specific OO concepts.
Again, thank you all for responding.
Curt Welch - 05 Dec 2007 02:15 GMT jattardi@bluesocket.com wrote:
> > His statement is true for any base object that get extended, not just > > core object of the language. Any object can be "enhanced" -- for lack [quoted text clipped - 13 lines] > > Does that make any sense? I haven't had my coffee yet... That's true.
The additional risk it creates is that you force the users of your code, to update there code as well when the third party changes the superclass code. With inheritance, the users of your code inherent not only your work, but the work of people who created the superclass - so you expose them to twice as much potential change than if you use composition and isolate them from half that change.
I always tend to favor composition over inheritance because it tends to reduce the dependency between code and reduce future bugs and increase the ease of future changes. Inheritance is probably the single most important feature of OO languages, but it should be used with care. It should never be used just because it's the easy and fast solution to a coding task. Minimizing current coding time or code length is seldom the prime factor to consider when making these decisions. Most code worth writing will live a long life and it is all the future problems you can create or avoid by making the wrong or right decisions at the start that tend to be the most important.
 Signature Curt Welch http://CurtWelch.Com/ curt@kcwc.com http://NewsReader.Com/
Daniel Pitts - 03 Dec 2007 15:56 GMT >>> Thanks in advance for your responses. >>> I am relatively new to OOP and though I have muscled my way through [quoted text clipped - 101 lines] > > cj The true benefit from OO comes when you learn to decouple your system as completely as possible, without disintegrating it. When you're code model works well, but you can replace the implementation on any non-trivial module without breaking the existing implementation of any other module, you've achieved the "perfect" design.
most designs aren't that perfect, and that's okay. As long as you're ready to make some changes as other changes happen. Externally managed modules make it difficult to ensure this rule, as the API may change over time in incompatible ways.
 Signature Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
Lew - 03 Dec 2007 16:35 GMT > But Mr Welch noted something which disturbs me about the entire > concept of OO. Specifically, Mr Welch wrote: [quoted text clipped - 11 lines] > with an object extending it. Does not his statement belie the > "benefits" of OO, perhaps highlight a real danger in using OO? You are exactly right. This particular danger is called, "making a class heritable without planning for the consequences". It's a topic covered very well, among other places, by Joshua Bloch in his vital /Effective Java/ book. The problem is that when you make a class heritable, you are exposing much more of its implementation to other folks, folks who don't know you, folks who don't have your goals in mind or at heart, folks who can do surprising and damaging things if you don't lock certain gates.
"I didn't realize that getFoo() could yield a completely different behavior if its helper method barBaz() was overridden."
The prevention in that particular case is to declare the barBaz() method 'final', i.e., forbidden to be overridden. A well-designed heritable class locks down behaviors that subclasses should not mess with. It does not call overridable methods from constructors. It is very close with its access privileges, rarely straying into package-private, much less protected or public exposure. It also will change its exposed interface very, very rarely, if ever. Superclass "enhancements" can break subclass behavior, too.
It seems we programmers just don't get power in a language without the responsibility to use it wisely.
 Signature Lew
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|