Looking for bad design in the Java 1.0 data structures is like shooting fish in a barrel.
Yes, Stack is a badly designed class. It should not have been a class in the first place, it should have been an interface. I'm dissapointed it has not been deprecated and replaced.
I have yet to meet someone using that class. The fact that you suggest UnicastRemoteObject as a "more widely known example", a class specific to distributed application development versus a basic data structure, says a lot about it.
But that's why the data structures framework was completely redesigned in Java2, to correct many of those mistakes.
There is no Java2 equivalent for the Stack, but we could figure how one would look from the general pattern of the other Java2 Collections: List and Set.
public interface Stack extends Collection
public Object pop();
public Object push(Object item);
public Object peek();
public class AbstractStack extends AbstractCollection implements Stack
public class ArrayStack extend AbstractStack
private ArrayList array = new ArrayList();
//If you really want to use Vector for thread safety
public class VectorStack extends AbstractStack
private Vector array = new Vector();
public class LinkedListStack extends AbstractStack
private LinkedList array = new LinkedList();
There it goes: inheritance used for IS-A (with code reuse when it makes sense and is part of an IS-A relationship), object composition for code reuse in the implementation.
Now, with respect to the UnicastRemoteObject, from the Javadocs:
The UnicastRemoteObject class defines a non-replicated remote object whose references are valid only while the server process is alive. The UnicastRemoteObject class provides support for point-to-point active object references (invocations, parameters, and results) using TCP streams.
Objects that require remote behavior should extend RemoteObject, typically via UnicastRemoteObject. If UnicastRemoteObject is not extended, the implementation class must then assume the responsibility for the correct semantics of the hashCode, equals, and toString methods inherited from the Object class, so that they behave appropriately for remote objects.
I'm not a distributed computing guru, but it would seem to me there are some conceptual restrictions to this UnicastRemoteObject: when are the references valid, how does it communicate (only TCP), and the fact that it's a Server.
These are limitations you don't want in your basic abstract type. Implementation issues that should not percolate to every RemoteObject in the system, especially not to Client objects (that's why RemoteServer is there).
It exists not just for programmers to extend it, but to provide a type in the hierarchy at the correct abstraction level: it IS-A RemoteServer, and therefore IS-A RemoteObject, but it is an specialization for TCP communication of these types. It exists to remove communication-specific details (TCP) and other implementation issues from the abstract data type where they do not belong, but which may be a common need for a lot of subclasses... not just the code, the functionality per se (the interface).
This is a default implementation, of course. But as an specialization of the RemoteObject and RemoteServer types, with the additional methods and contract assumptions, it deserves its own place as a type.
I think a better example, and perhaps more widely known, of a purely pragmatic use of inheritance would be javax.servlet.GenericServlet.
That class seems to have no reason to exist except to provide implementation for already defined methods (I don't see why its extra methods could not have been in the original Servlet interface).
But it's a safe use of inheritance for code reuse because it is not forcing the "IS-A" relationship. The GenericServlet "IS-A" Servlet still.
Code reuse is not BAD, nor is inheritance independent of it. The point is that code reuse is a SIDE EFFECT of inheritance. Sometimes you need the side effect, sometimes you depend on it, and sometimes it's the only thing you wnat.
But if it's the only thing you want, there are better ways of achieving it, and you don't need inheritance. Just like in normal coding, programming based on side-effects when you have direct, better means of achieving what you want can be seen as either stupid or a clever way of getting in trouble.
Freedom is the freedom to say 2+2=4, everything else follows...
[ Parent ]