File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes Design review Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Certification » Developer Certification (SCJD/OCMJD)
Bookmark "Design review" Watch "Design review" New topic
Author

Design review

Chiji Nwankwo
Ranch Hand

Joined: Jun 21, 2002
Posts: 56
Hi all,
Could you please read my design and tell me if there are any holes. Comments are very welcome and will be much appreciated.
Client GUI:
ConnectionDialog (modal) - user needs to provide file location, if running in local mode, or host name / ip and port number
if running in remote mode. a successful connection will hide this dialog and return focus back to the MainView.
BookingDialog (modal) - shows the user a snapshot of the flight details and number of seats entered and gives the user the
option to either cancel or make a booking. a successful booking will hide this dialog and return focus back to the MainView,
with the number of seats in the results table being reduced by the number of seats booked or removed from the table
completely if all the seats are booked.
MainView - the user can choose to disconnect and reconnect to either local or remote connections. choosing to reconnect will
display the ConnectionDialog again. clicking on the confirm button will cause the BookingDialog to be displayed.

Client:
MainController - data is passed to this class by Actions (SearchAction, ConnectAction, BookAction ...), which are contained
within the MainView class. the data passed to this class is used to set values in the ClientModel, which is listened to by
the MainView class.
DataClient - is an interface implemented by the AbstractDataClient, that contains all the methods of the remote interface.
AbstractDataClient - implements DataClient and provides behaviour that needs to be implemented by its subclasses.
LocalDataClient - extends AbstractDataClient and is used by clients that do not require networking functionality.
RemoteDataClient - extends AbstractDataClient and is used by clients that require networking functionality.
DataClientFactory - is used to instantiate DataClient objects (local or remote).
TravelAgent - serves as a facade to the DataClient instances, providing business methods like, searchFlights, bookFlights
etc.
Mediator - handles the interaction between all the components contained on the GUI's. so all the logic for enabling /
disabling buttons, actions, clearing text fields etc are contained in one class. on initialization, components need to
register themselves with the mediator.
ClientModel - provides an interface, which the view accesses in order to update itself. when certain methods (set methods)
within this class are invoked, a ClientEvent is sent to all this models ClientListeners.
DefaultClientModel - is an implementation of the ClientModel interface and provides methods which can be used to set values
contained in the model. only the controller has access to this class.
ResultsTableModel - is a subclass of AbstractTableModel and is used by the JTable for displaying search results.

Data:
DataExtension - is an interface that contains all the public / protected methods, which are contained within the provided
Data class as well as criteriaFind.
DataExtensionImpl - implements DataExtension and provides an implementation for the criteriaFind method. this class creates
a Data instance and delegates all method calls except for the call to criteriaFind to the Data class instance. any calls
made to the criteriaFind method are handled by this class as it is not implemented in the Data class.

Server GUI:
ServerAdministrator - is a server console that has buttons to start and stop the server. it also provides tabbed panes which
contain text panes for displaying of status and connection information on the server side.
Server:
DataService - remote interface that is provided to the Client, which is used to interact with the Data class via the
DataExtension class.
DataServerImpl - implements DataService. this class keeps a list of all the clients that are connected to it. each instance
of this class has a DataExtension and a LockManager instance. all the method calls except for lock and unlock, are forwarded
to the DataService instance. The lock and unlock calls are forwarded to the LockManager instance. each LockManager instance
is tied to a DataExtension instance via this class. all the clients that share the same DataServer instance will also share
the same LockManager and DataExtension.
DataServiceFactory - remote interface that is registered with the rmi registry. clients get a reference to this object from
the registry and use this object to access a reference to the DataService object.
DataServiceFactoryImpl - implements DataServiceFactory. creates and keeps a list of DataService, LockManager and
DataExtension instances. each DataService instance that is created is passed a DataService and LockManager instance. this
class makes sure that only a certain number of DataService instances are created.
LockManager - interface that is used by the DataServerImpl class to forward calls to the lock and unlock method to the
LockManagerImpl class.
LockManagerImpl - implements LockManager. keeps a record of all the record locks and clients that are waiting for locks.
each instance of this class contains a daemon thread, which is started when the instance is created. when there are no locks
available, the thread that runs within this class, waits for an indefinate amount of time. when locks are present this class
waits for specified amount of time (default 10 seconds). when locks are present in this class the thread wakes up after a
specified amount of time and clears out any locks that have been held for longer than the specified timeout.
Connection - this is an immutable, serializable object that represents a unique client connection. this is object is created
and stored in the RemoteDataClient class and is registered with the DataService class. this is the object that is passed to
the DataService instance whenever a client needs to lock or unlock a record.
Thankyou for getting to this stage. comments are very welcome.
Regards,
Chiji


SCJP, SCJD, SCWCD<br />"Meekness is not weakness, but power under control"
Peter den Haan
author
Ranch Hand

Joined: Apr 20, 2000
Posts: 3252
Originally posted by Chiji Nwankwo:
BookingDialog (modal) - shows the user a snapshot of the flight details and number of seats entered and gives the user the option to either cancel or make a booking.
The network call can take some time, especially in an internet/VPN environment. Are you using worker threads to keep the GUI responsive?
[... a flight is] removed from the table completely if all the seats are booked.
Have you considered that it may not be clear to the operator whether a flight is fully booked or whether (s)he just mistyped origin or destination?
DataClient [...] AbstractDataClient [...] LocalDataClient [...] RemoteDataClient
What is the rationale behind this? Wouldn't it be much simpler and just as effective to have Data (or DataExtensionImpl), and (the RMI stub of) some server-side object which implements the same interface, and use that?
DataClientFactory
What benefit does this factory class give you over just having some code related to your connection dialog that instantiates the right flavour of object?
TravelAgent - serves as a facade to the DataClient instances, providing business methods like, searchFlights, bookFlights
[QB]ClientModel - provides an interface, which the view accesses in order to update itself. [...] a ClientEvent is sent to all this models ClientListeners.
What's your rationale for introducing this above and beyond the bog standard TableModel, TableModelListener and TableModelEvent?
DefaultClientModel
What is the benefit? Do you anticipate having multiple implementations of this interface anytime soon?
DataExtension - is an interface that contains all the public / protected methods, which are contained within the provided Data class as well as criteriaFind.
What is your rationale for not simply incorporating the criteriaFind method into Data?
Server GUI:
Are you aware that the presence of a GUI makes it impossible to deploy the server on many Unix server systems? Often these do not have a graphical terminal attached to them simply because there's no need whatsoever. You can run graphical applications for configuration and so forth through remote X terminals. The server processes themselves do not need and should not have a GUI; it's simply another point of failure.
DataService - remote interface that is provided to the Client
I understand the client gets a Connection as well. Why two different objects? Can't the Connection simply implement the Data interface?
LockManager [...] LockManagerImpl
What's the rationale for using an interface?
You have clearly taken design patterns and many good design practices on board, which is excellent. My beef with your design is its sheer complexity; you seem to have designed this application as if you were designing an abstract, pluggable, highly layered framework. Design patterns are a good thing, but that does not mean you should use as many of them as possible
My SCJD instructions asked for a clear design, such as will be readily understood by junior programmers. Also, I tend to subscribe to the XP mantra to make a design as complicated as is necessary to fulfil the requirements, but no more. Others succinctly refer to the KISS principle (Keep It Simple, Stupid). While I have no doubt that you will pass, probably with a fine score, if you want to get the maximum out of the learning experience I suggest you look at your design with a critical eye and trim some of the fat.
- Peter
Chiji Nwankwo
Ranch Hand

Joined: Jun 21, 2002
Posts: 56
The network call can take some time, especially in an internet/VPN environment. Are you using worker threads to keep the GUI responsive?

the code that handles all the gui freezing logic is started in their own threads. This includes things like search, book and connect. this is an example of the book method contained within the controller.


Have you considered that it may not be clear to the operator whether a flight is fully booked or whether (s)he just mistyped origin or destination?

i did consider the user feedback element. when a flight is booked a BookingDetail object is returned from the facade, which is displayed to the user in a booking status portion of the screen. the Booking detail object contains such information as the flight number, the number of seats booked, the time of the booking and a status (confirmed, no seats available, not enough seats available or unconfirmed).
What is the rationale behind this? Wouldn't it be much simpler and just as effective to have Data (or DataExtensionImpl), and (the RMI stub of) some server-side object which implements the same interface, and use that?

could you please elaborate on this point. i will try explain it the way i understande. my rationale behind this is to have a representation of the DataService class on the client side and this is why i use a DataClient interface. the facade that contains the business methods asks the DataClientFactory for a DataClient instance, passing it the string 'remote' or 'local'. by doing this, the facade doesn't need to know whether it has reference to a remote or local object. AbstractDataClient contains abstract methods register and unregister, which are implemented in the RemoteDataClient but are empty in the LocalDataClient, it also provides constants for generic error messages and strings. when a LocalDataClient is created it constructs a DataExtension instance and uses this instance to interact with the db. on the other hand when the RemoteDataClient is created, it does a lookup and retrieves the DataServiceFactory from the registry and uses this instance to get a DataService reference.
What benefit does this factory class give you over just having some code related to your connection dialog that instantiates the right flavour of object?

i use this class as a seemless way for the facade to request for a DataClient instance, without having to worry about whether the instance returned is a LocalDataClient or a RemoteDataClient. are you suggesting that the ConnectionDialog should contain the logic that is used to create either a Local or Remote DataClient instance? see sample code, from the DataClientFactory, below,

What's your rationale for introducing this above and beyond the bog standard TableModel, TableModelListener and TableModelEvent?

my rationale behind this is to create a clean seperation between the view and data aspects of the GUI. the actions which are contained within the view have a reference to the controller and pass data like the number of seats, flight number etc to the controller. the controller, which has a reference to the model then uses the data that has been passed to it to set values within the model. once these values have been set, the listeners (ie the GUI) are notified and update themselves. i still use the TableModel, TableModelListener and TableModelEvent. the ResultsTableModel is contained within the view, so when the view is notified the values needed to populate the ResultsTableModel instance are retrieved from the view and used to initialize the ResultsTableModel instance.

What is the benefit? Do you anticipate having multiple implementations of this interface anytime soon?

has that possibility been ruled out? i thought one of the rationales behind this work was to design for reuse and to make modifications to the system relatively seemless.
What is your rationale for not simply incorporating the criteriaFind method into Data?

one of the ways in which an existing class can be modified is via extending a class. my whole idea for doing this was not to add any new features to the existing Data class. but you will probably be asking, "how did i ammend the depracated methods"? since i have made direct modifications to the Data class in the way of changing the depracated methods, i guess i can implement the criteriaFind method in the Data class. doing this will get rid of the DataExtensionImpl class, but i still think that the DataExtension interface is necessary assuming a new implementation needs to be created that talks to any SQL database for instance. or is this way out of line?

Are you aware that the presence of a GUI makes it impossible to deploy the server on many Unix server systems? Often these do not have a graphical terminal attached to them simply because there's no need whatsoever. You can run graphical applications for configuration and so forth through remote X terminals. The server processes themselves do not need and should not have a GUI; it's simply another point of failure.

i see the point you are making. but what if another ui was provided for the systems that do not support the GUI and instead of printing to a GUI it just printed out to the screen. i think the gui gives the adminstrator an effective way to stop and start the server as well as giving an adequate snapshot of what is going on with the system in terms of connected users, locks, deadlocks and all the other info that the GUI provides.
I understand the client gets a Connection as well. Why two different objects? Can't the Connection simply implement the Data interface?

yes the client does get a connection as well. the reason i don't use the DataService is because i do not create one unique DataService instance per client. the DataServiceFactory has a maximum number of DataService instances that can be created. this means that many clients can share the same DataService instance. this is where the Connection object comes into play. the connection object is made up of information from the DataService instance (server id) and information from the RemoteDataClient instance (client id). I use the factory to limit the number of DataService instances that are created. as i explained in my previous post, each DataService instance, which can be shared by various clients, has a DataExtension instance and a LockManager instance.
What's the rationale for using an interface?
You have clearly taken design patterns and many good design practices on board, which is excellent. My beef with your design is its sheer complexity; you seem to have designed this application as if you were designing an abstract, pluggable, highly layered framework. Design patterns are a good thing, but that does not mean you should use as many of them as possible

i created the LockManager interface to make it easy for its underlying implementation to be changed with minimal impact on the system. the LockManagerImpl is not tied to the system in any way, can be swapped out any time with another implementation and represents a generic way of dealing with locks. see interface below.

my aim is to make the system easy to understand by decoupling functional parts of the system and the at the same time making sure the system can be modified and reused without a great deal of disruption.
Should I assume that the only parts you commented about are the parts you had beef with or was that you limit? I really appreciate this. By time I am done defending my work on the forum, I think I will be ready to write a couple of essays.

Regards,
Chiji
Chiji Nwankwo
Ranch Hand

Joined: Jun 21, 2002
Posts: 56
Hi,
Does anyone have anymore comments on the above design? Your comments are very welcome.
Regards,
Chiji
Peter den Haan
author
Ranch Hand

Joined: Apr 20, 2000
Posts: 3252
the code that handles all the gui freezing logic is started in their own threads
Smashing.
[Re: DataClient and friends] could you please elaborate on this point. i will try explain it the way i understande.[...]
It is clear how it works, but it still seems to be an entire layer that could be cut out without significant functionality or flexibility loss. What prevents your business object from talking to Data directly (in local mode) or to your remote flavour of Data (in networked mode)?
The error messages seem out of place here. That's user interface stuff, whereas DataClient is sitting in the business logic <==> database interface, well away from the UI. By the way, my boilerplate systems architecure diagram is:
UI <==> business logic <==> database
There's this requirement that you have a client-side object implementing the Data interface. This effectively means you have a "local Data" and a "remote Data". You appear to have another layer around that that also has local and remote implementations. That sounds wrong to me.
i use this class as a seemless way for the facade to request for a DataClient instance, without having to worry about whether the instance returned is a LocalDataClient or a RemoteDataClient. are you suggesting that the ConnectionDialog should contain the logic that is used to create either a Local or Remote DataClient instance?
You could simply pass the right DataClient in as a constructor argument. I would not put this code in the dialog itself -- personally, I just had a small static method in my main class that instantiated the right objects and glued them together at startup. I don't think a factory would have gained me anything there. There's simply not enough substance to it to justify yet another class.
my rationale behind [ClientModel] is to create a clean seperation between the view and data aspects of the GUI.
I agree with the necessity of a ClientModel class, but does it need to be a full-blown observable? Isn't it enough to just have a getTableModel() method?
Of all my points this may be the most contentious. It is perfectly legitimate to say no, I don't want to marry my ClientModel to a Table. It is an abstract model which needs to be observable in its own right, and the TableModel is just one of the ways to adapt it to Swing. It depends on how you view this application, whether you think there will be many other view types (in which case your approach is fine) or whether you think that the model class merely exists to neatly package concerns and achieve the separation you are talking about (in which case you can simplify your code).
has that possibility [of multiple ClientModel implementations] been ruled out? i thought one of the rationales behind this work was to design for reuse and to make modifications to the system relatively seemless.
There is a profound difference between application development and framework development. In this application, I have difficulties seeing a need for a second ClientModel implementation. I would contend that reasonable future growth can be catered for by simple modification.
Keyword "reasonable". One of the lessons taught by XP (Extreme Programming) is that it is useless to anticipate change too far ahead. You can try, but you will be wrong. XP argues that it makes much more sense to provide a clean but simple design that can easily be changed, than with a design that attempts to cover every eventuality, inevitably fails, and turns out to be complex to modify.
my whole idea for [DataExtension] was not to add any new features to the existing Data class.
Why is that a good idea?
Let me explain a bit. One of the most useful ways to look at OOP&D (object oriented programming & design) is in terms of responsibilities. An ideal design is one in which each class as a single, well defined responsibility. The question then is, how do you distinguish the responsibilities of Data and DataExtension without running into problems? In particular, what is so special about the criteriaFind functionality that it does not fall within Data's existing responsibility?
My own conclusion was that the responsibility of Data was to "provide access to a single local table with an arbitrary structure". Then I looked at what criteriaFind was doing and found that it fell squarely within that definition, so it had to go into Data. Another consequence was that criteriaFind would be completely generic and not tied to the FBN table structure -- I assume that's what you've done anyway. Yet another consequence was that I did not put any networking support whatsoever in Data; in particular, lock() and unlock() remained no-ops.
i see the point you are making [about server GUIs]. but what if another ui was provided for the systems that do not support the GUI and instead of printing to a GUI it just printed out to the screen.
Excellent. Be sure to put a sentence or two in your design documentation, so the assessor can see you have thought about these matters.
yes the client does get a connection as well. the reason i don't use the DataService is because i do not create one unique DataService instance per client. the DataServiceFactory has a maximum number of DataService instances that can be created. this means that many clients can share the same DataService instance. this is where the Connection object comes into play.
What are you trying to achieve? Are you trying to limit the number of remote objects you have to create because they are rather heavyweight? They are, but my instructions specifically said that you were not to compromise the simplicity of your design for performance reasons. Very good advice indeed. Many a system was rendered hard to maintain by premature and misdirected "optimisation". Optimisation is something you do at a later stage, with a profiler to back your theories up. But I digress.
If you would simply give each client its own remote object to talk to, a single object implementing all the methods it would need to call, that could simplify the design a fair bit. Given Sun's instructions, this Connection object would basically expose all public methods of the Data class.
i created the LockManager interface to make it easy for its underlying implementation to be changed with minimal impact on the system. the LockManagerImpl is not tied to the system in any way, can be swapped out any time with another implementation and represents a generic way of dealing with locks.
I would contend that you have achieved nothing here that could not be achieved just as easily with modification or replacement of a LockManager class that does not implement any particular interface.
See the point above about framework versus application development.
Should I assume that the only parts you commented about are the parts you had beef with or was that you limit?
Those were the only parts I had something sensible to say about. Well, something to say about, sensible or not The rest looked top notch to me.
I hope I'm not causing you any distress by giving the design such a grilling. As I said, it is a fine design and I'm convinced that you would easily pass if you'd submit it as is. I assumed that one of the reasons you posted the question is that you wanted to make the most of the SCJD experience, and few things are better for that than this type of detailed, in-depth, and sometimes pedantic discussion.
- Peter
[ December 03, 2002: Message edited by: Peter den Haan ]
Chiji Nwankwo
Ranch Hand

Joined: Jun 21, 2002
Posts: 56
It is clear how it works, but it still seems to be an entire layer that could be cut out without significant functionality or flexibility loss.

My business object is not aware of what type of DataClient it is connecting to. The DataClient interface is implemented by both the RemoteDataClient and LocalDataClient instances. The DataClient interface contains all the public methods which are implemented in the Data class. When a LocalDataClient is created, it constructs a Data instance which it stores. Subsequent calls that made to the LocalDataClient are delegated to the Data class. On the other hand, when a RemoteDataClient is created it gets a reference to a remote DataService instance via the DataServiceFactory, which is also remote and registered with the registry. Subsequent calls made to the RemoteDataClient are delegated to the DataService instance.
The only difference between the DataService and DataClient interfaces, apart from the fact that DataService is remote, is the fact that DataService contains two additional methods namely register and unregister. These two methods are called when a client connects and disconnects from the system. The register method is used to store the connection object within the DataService implementation. When you refer to a 'Data interface' and I refer to a 'DataClient', are we referring to the same thing?
The reason I have placed the error messages where I have is due to the fact that both my DataClient implementations rethrow a custom exception (DataClientException). Most of the methods in the DataClient interface specify a DataClientException as part of their signature. The methods within the the DataService, remote, interface are capable of throwing both a RemoteException and a DatabaseException, whereas the Data class only throws a DatabaseException. The RemoteDataClient instance will rethrow a DataClientException, which can contain an appropriate message for either a RemoteException or a DatabaseException. The LocalDataClient instance rethrows a DataClientException that only contains a message for a DatabaseException.
You could simply pass the right DataClient in as a constructor argument.

My controller class, is aware of the fact that it has an instance of the business object and nothing else. The controller retrieves the connection mode and parameters (data name, host name or port), from the GUI and passes this information on to the business object. I reckon that the businesss should be in charge of either creating the next link in the pipeline or passing control over to an object that will. My controller class' main responsibility is to handle communications between the view and the model of the GUI. In my case the client can disconnect and reconnect from the application without restarting the application. Selecting a reconnect menu option will redisplay the original, modal, ConnectionDialog. This is one of the main reasons why I can't instatiate the right objects and glue them together at startup. My spcification says, "The user must be able to select the operating mode, although it is acceptable that the program stay in one mode once it has started up". I opted to give the user the option to disconnect from or reconnect to either a local or remote connection.
I agree with the necessity of a ClientModel class, but does it need to be a full-blown observable?

I have other areas of the GUI that need to be updated a direct result of a connect, disconnect, search, confirm and book action. This is why I went for the "full-blown observable" option. As I explained earlier on, once the main GUI is loaded the user has the option to either disconnect or reconnect to the application. My GUI consists of three parts (ConnecitonDialog, BookingDialog and MainView), which all share the same model. The MainView has a reference to a ConnectionDialog and BookingDialog instance. I had considered providing a getTableModel() method and then I thought, about giving the view the option to display the results in which ever way they choose.
There is a profound difference between application development and framework development.

I will re-examine this.
Why is that a good idea?

I agree with the first paragraph and will re-examine the role of the DataExtension class. "Another consequence was that criteriaFind would be completely generic and not tied to the FBN table structure -- I assume that's what you've done anyway." I do not understand what you mean by this statement, could you please explain.
Excellent. Be sure to put a sentence or two in your design documentation, so the assessor can see you have thought about these matters.

When the server admin program is run I am posing a question to the administrator like, "Would you require the GUI or NON-GUI mode?" How does that sound?
What are you trying to achieve? Are you trying to limit the number of remote objects you have to create because they are rather heavyweight?

Yes, that is my aim. I am trying to implement some sort of pool management on the server-side. If I was to give each client its own remote object to talk to, then I do not see the need for a Connection object as the Connection object is merely used by the client to identity itself on the server when it calls the lock and unlock methods on the remote DataService instance.
I would contend that you have achieved nothing here that could not be achieved just as easily with modification or replacement of a LockManager class that does not implement any particular interface.

I provided the interface to both the DataExtension and LockManager, which are used by the DataService implementation because they can both exist without the DataService implementation but the DataService implementation can not exist without them. I guess you could argue that for the purposes of this assignment they need to co-exist with each other. I was thinking of the DataExtension and LockManager interfaces are reuseable classes.

No distress is being caused at all! I am glad my design is getting the grilling that it is, which is one of the main reasons why I posted my design in the first place. I am very open to constructive critism, I feel it is very necessary in order to succeed.
Regards,
Chiji
Chiji Nwankwo
Ranch Hand

Joined: Jun 21, 2002
Posts: 56
Any comments?
Max Habibi
town drunk
( and author)
Sheriff

Joined: Jun 27, 2002
Posts: 4118
Hi Chiji,
I think your approach is a good one: There are stylistic elements that I might have handled differently, but that's no guarantee that means 'better'. It sounds like you've taken a careful approach, and that's all that can be expected.
You should probably give the application to an unsuspecting friend to test(and don't give him any verbal instructions other then very broad ones: if he can't figure it out from you readme, then you're not being clear), and submit your assignment. After that, I suggest that you take the essay exam ASAP, while everything is still fresh in your mind.
All best,
M, author
The Sun Certified Java Developer Exam with J2SE 1.4


Java Regular Expressions
Chiji Nwankwo
Ranch Hand

Joined: Jun 21, 2002
Posts: 56
Hi,
My understanding of the the part of the requirement that says, "To connect with your server, you should create a client program. This implementation should include a class that implements the same public methods as the suncertify.db.Data class, although it will need different constructors to allow it to support the network configuration." Is shown below. Can anyone please tell me if this correct.

quote:
--------------------------------------------------------------------------------
You could simply pass the right DataClient in as a constructor argument.
--------------------------------------------------------------------------------
My controller class, is aware of the fact that it has an instance of the business object and nothing else. The controller retrieves the connection mode and parameters (data name, host name or port), from the GUI and passes this information on to the business object. I reckon that the businesss should be in charge of either creating the next link in the pipeline or passing control over to an object that will. My controller class' main responsibility is to handle communications between the view and the model of the GUI. In my case the client can disconnect and reconnect from the application without restarting the application. Selecting a reconnect menu option will redisplay the original, modal, ConnectionDialog. This is one of the main reasons why I can't instatiate the right objects and glue them together at startup. My spcification says, "The user must be able to select the operating mode, although it is acceptable that the program stay in one mode once it has started up". I opted to give the user the option to disconnect from or reconnect to either a local or remote connection.

My DataClient class contains all the public methods which are contained in the Data Class. I have an AbstractDataClient, which implements the DataClient interface. I also have a RemoteDataClient and LocalDataClient class to handle remote and local connectivity respectively. The class that contains an instance of the DataClient class has no idea whether it contains a Remote or Local DataClient instance. Is this line of thinking correct?
Regards,
Chiji
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Design review