I'm working on URLyBird. I must implement specified interface. "Your data access class must be called "Data.java", must be in a package called "suncertify.db", and must implement the following interface:" I thought of using 3-layer approach.
There's a choice here. Personally I decided to make the Data class a proxy for the actual database file operations. So Data just translates calls to read and write records and recordsets and forwards those to a DataFile which does the actual database operations.
I've provided 2 distinct versions of the Data class, one being a proxy to a Data class instance that is provided to network clients and handles network traffic as well.
Could you elaborate on this or say it in different words. Did you mean that you provided two different versions of the class as part of your submitted project? If so, what did you do? Did you have two classes extend from an abstract class, or do you mean something else? Thanks.
Jeroen T Wenting
posted 13 years ago
RemoteData is a decorator for Data which is itself a proxy for the DataFile and MetaData.
MetaData and DataFile are abstract, actual versions for the real database are linked into the Data instance by the factory which is responsible for creating them. [ May 19, 2006: Message edited by: Jeroen T Wenting ]
I am not answering for Jeroen - hopefully he will come back and give his own answers. But my take on Jeroen's comments is:
Having the Data class as a Proxy, or having it as a Facade, allows us to keep the idea of having each class having a distinct set of responsibilities.
So the MetaData class is responsible for handling anything to do with metadata. The DataFile class is responsible for handling anything to do with the data file itself. There may also be seperate classes that just handle locking. Finally the Data class is responsible for providing access to all the other classes.
I suspect that the MetaData class and the DataFile class will only allow package level access, forcing users to go through the public methods of Data class to get access to the data.
Since we have division of responsibility, I know that if I need to look at something to do with the meta-data, I will go to the MetaData class. I will not need to look at several hundred lines of code that are specific to data-file access, since they are off in their own class.
In eXtreme Programming, one of the recommend practices is to try and avoid the use of the word "AND" when describing a class or method. As soon as you have to use the word AND, there is the potential that your class or method may be doing too much, and should be refactored. As mentioned a paragraph ago, this might only have the benefit of removing extraneous code (which makes your code easier to read / maintain), but it might also result in fewer cases where unrelated sections of code affect each other in unexpected ways just because they are within the same class and have access to everything else within the class.
The Data class provided by Sun is a classic case where you might want to look at having either a Proxy or a Facade (and what the differences are, and which to use is a seperate discussion). If Data class does everything itself, then you have one large class that contains all the locking code, AND all the data access methods, AND all the meta-data handling, AND all the schema handling. Just refactoring into an additional two classes - one for lock handling and one for anything related to the file - will result in much cleaner, simpler to understand code.
Hope this gives you some idea of why you might want to split classes.
Jeroen - time for you to shoot holes in anything I got wrong in general or in my interpretation of your specific comments
That was pretty much my reasoning. I made a separate RemoteData to wrap Data so the client will have a consistent programming interface. All it ever sees is Data, even if in reality it has a RemoteData (only the factory knows what it's returning depending on how it was called).
When a RemoteData is returned (which is a Facade around Data) the client actually gets a DataProxy which wraps the RemoteData (which itself is a Data that adds the networking stubs) so it becomes a Data again, by handling the network related exceptions.
So Data is the place where the ACTUAL calls are handled, RemoteData adds the networking stuff to that, DataProxy then acts as a proxy and hides the networking stuff from the client so it doesn't have to bother about that. All it sees is errors in the database functionality, with a description. It never gets a RemoteException, doesn't even want to.
So RemoteData has among others
which gets turned back into a direct call to a Data through the DataProxy:
and Data has simply
So the client never has to know or care about whether it is a local or networked database except at the point of requesting the connection from the ConnectionFactory.
The flexibility here is enormous. I can change the network stub to something else and the client never need know. I can change the database format to something else and all that needs changing is the actual DataFile class derivative (DataFile is an abstract base for the actual database format, so I can add more formats by changing the factory and adding another DataFile derived class).
I may have gone overboard, but better safe than sorry when the specs say the application should be open for change
posted 13 years ago
Thanks Andrew/Jereon, both your posts are great.
I've just been reading about decorators and this a great real world example.