Hi Guys, Could someone explain the benefit of placing the lock and unlock methods in the DataInterface when they are only required for remote connections? Is there anything wrong with creating a DataInterface with all the public methods of Data except lock and unlock. Also add criteriaFind() to this interface. Data class then implements DataInterface. Then you create a RemoteDataInterface that extends Remote and defines the lock and unlock methods.Then create a RemoteData extends Data and implements RemoteDataInterface. For local connection you will use Data and for remote connection RemoteData. Please advise?
Originally posted by Fred Barnes: Could someone explain the benefit of placing the lock and unlock methods in the DataInterface when they are only required for remote connections? Is there anything wrong with creating a DataInterface with all the public methods of Data except lock and unlock.
Yes. There is a lot wrong with that. Let me answer your question by taking a step back and look at the nature of inheritance. (Don't despair, I will get to the point soon enough; this is important). We all know that inheritance models an "IS-A" relationship. For example, a java.zoo.Cow "IS-A" java.zoo.Animal. A slightly more formal way to look at it is to say that a subclass should satisfy the substitution principle: wherever you can use an instance of the base class, you should be able to use an instance of the subclass. This applies to interfaces as well as classes. All the rules of the Java language with regards to inheritance, overloading, narrowing of exceptions in subclasses and so forth serve to satisfy the substitution principle on the language level. What is much less appreciated by developers is that this is only part of the story. YOU will have to satisfy that the substitution principle is satisfied on the implementation level as well as the language level. This is one of the prerequisites for good OO design. In particular -- see, I'm coming to the point after all -- "RemoteDataInterface extends DataInterface" means that you should be able to substitute RemoteDataInterface implementation wherever you use DataInterface implementation. But wait. To work properly with remote implementations, you need record locking! So, unless you add lock() and unlock() methods to DataInterface, you cannot possibly satisfy the substitution principle. Let's look at it from a purely practical point of view. If you would do what you're suggesting and leave locking out of DataInterface, you would effectively end up with code likeIt doesn't have to look this way at all, but it would boil down to this whatever you do. And it is horrid code. Polymorphism was introduced exactly to do this kind of thing -- vary the implementation for an action (method) depending on the type. When the lock methods are in DataInterface, you would simply sayIf db happens to be local, this call would do nothing. That's fine. You don't care. Polymorphism and the substitution principle ensure that the right thing happens when you call lock(), whatever the right thing might be. A third way of looking at this -- and then I'll shut up -- is that you misunderstand the nature of DataInterface. It is not a "local database". After all, a "remote database" IS-NOT-A "local database"; the inheritance is all wrong. DataInterface is the interface implemented by a "database of any kind". And, of course, as befits an interface which is completely agnostic about the type of database it implements, it has the lock() and unlock() methods that are needed in a networked multi-user implementation. Let's verify the relationships: a "remote database" (RemoteDataInterface) IS-A "database of any kind" (DataInterface). Check. A "local database implementation" (Data) IS-A "database of any kind" (DataInterface). Check A "remote database implementation" (RemoteData) IS-A "remote database" (RemoteDataInterface). Check. HTH - Peter
Hi Peter, Just a quick question. If DataInterface represents a database of any kind should the method signatures not change to be more generic?
For example: public FieldInfo getFieldInfo(); should be public Object getFieldInfo(); and public DataInfo getRecord(int recNum) throws DatabaseException; should be public Object getRecord(int recNum) throws DatabaseException; Your comments will be much appreciated. Regards Fred
Originally posted by Fred Barnes: [...] If DataInterface represents a database of any kind should the method signatures not change to be more generic?
Now you're overshooting the mark Maybe I should have said a "Data-like database of any kind". But then the sentences would've gotten rather long DataInterface indicates what the database API should look like, regardless of the implementation. This interface should be general enough to accomodate all reasonable implementations, but no more general than that. Make it too general, as in your example, and it becomes unworkable. How do you know what type of Object you're getting back? How do you know what to cast these Objects to without worrying about the type of DataInterface implementation you're using? -- you should never have to be aware of the implementation type! - Peter