Click to See Complete Forum and Search --> : help with design
ChessMaster
June 10th, 2008, 12:49 PM
I have an application which contains an UI. The UI displays data which is obtained from a server using web services. Since responses are delayed, i need a mechanism to update the UI whenever my data is available after my request. I am unsure if i am moving in the right direction with my design. I would appreciate any help i would receive related to the same.
Our application is a windows based application. It will communicate with the server using web services. Following is a high level design of how i intend to proceed. (I have used a different object in the example, since it would be easier to explain my problem)
I have more than one question related to the design, and hence I would like to ask them in a systematic way. I hope this is of no inconvenience to anyone.
Basic Idea related to my design is as follows,
We have a user interface class (displays employee(s) details..), an employee manager class (manages - create\delete\update...), an employee class (gets a particular employee detail like name, id...) & and an WebServiceGateway class (talks to the web service using the methods that are exposed by the web service at the server - uses xml for request and response).
User requests data for a particular employee. On this event, we request EmployeeManager class to get details for an employee. Employee manager class communicates with the web service using the WebServiceGateway class (async communication - hence he requests and returns immediately). When data is available the WebServiceGateway class can inform through (lets say a callback function) that data is available.
Now when the data is available, i need to inform\update the UI, through the EmployeeManager class - using the WebServiceGateway (of course). How do i accomplish this??
Following is the design that i have come up with so far.
class UserInterface
{
public:
GetEmployeeDetailEvent();
UpdateUIWithData(someDataFormat);
};
class Employee;
typedef std::list<Employee> EmployeeList;
class EmployeeManager
{
public:
void CreateEmployee (Employee& hiredForNow);
void DeleteEmployee (Employee& firedForever);
void UpdateEmployee (Employee& heGotHike);
void ListEmployees (EmployeeList& weHavePower);
void GetEmployeeDetail(Employee& underScrutiny);
};
struct Employee
{
std::string m_Name;
int m_ID;
};
class WebServiceGateway
{
void createObject(string request); //Used to create employee
void deleteObject(string request); //delete employee
void getObjects(string request); //get employee(s) details
//...
};
ChessMaster
June 10th, 2008, 01:04 PM
Also kindly let me know if there are any shortcomings with my design, and how to improvise.
Graham
June 10th, 2008, 01:13 PM
The first thing to do is to uncouple as many things as possible. You have:
Employee data. This may change at any time, and may be uninitialised.
A means of displaying that data (the UI).
A means of retrieving the data (the web services).
To me, this immediately says Observer pattern (two of them).
Firstly, the UI should be an Observer of the Employee data. In this way, it can be informed of changes and retrieve the new data.
Secondly, the Employee manager is an Observer of the web services, so that it can be told that data is available.
So, what happens is
UI requests data for a particular employee.
Employee manager issues request to web services, and returns "uninitialised" to the UI (if data is available it can return that).
Data comes back from web services, which informs the employee manager through the observer interface.
Employee manager fills in the employee record and tells the UI through its observer interface that new data is available.
UI requests the data and displays it.
The important thing here is that the UI is completely uncoupled from the details of how the data is retrieved: you could change the retrieval method and the UI would still work as before.
OK, that's a very quick description based on a few minutes' thought about it. If anything's not clear, just ask and I'll try to expand on it.
ChessMaster
June 10th, 2008, 01:25 PM
thanks for the quick response
I have just started reading craig larman's very famous book. So still a long way to go for me!
I will look through the observer pattern, modify my design and come with more inquires :)
Graham
June 10th, 2008, 02:32 PM
Just remember the three basic rules: uncouple, uncouple, uncouple. The more you can free elements of your design from reliance on the implementation details of other parts, the more robust your program will be.
ChessMaster
June 11th, 2008, 02:15 PM
i have modified the design. now using the observer pattern.
I have implemented for only one layer, the next layer (WebService) i can implement in the same manner.
struct CEmployee;
class IEmployeeManagerListner;
typedef std::list<CEmployee> EmployeeList;
typedef std::list<IEmployeeManagerListner*> EmployeeManagerListnerList;
class CWebServiceGateway
{
void createObject(std::string request); //Used to create employee
void deleteObject(std::string request); //delete employee
void getObjects(std::string request); //get employee(s) details
//...
};
struct CEmployee
{
std::string m_Name;
int m_ID;
};
class IEmployeeManagerListner
{
public:
virtual void CreateEmployeeEvent (CEmployee& employee) = 0;
virtual void ListEmployeesEvent (EmployeeList& employeeList) = 0;
};
class CEmployeeManager
{
public:
void CreateEmployee (CEmployee& employee);
void ListEmployees (EmployeeList& employeeList);
void AddListner(const IEmployeeManagerListner *const newListner)
{
empManListnerList.push_back(newListner);
}
private:
EmployeeManagerListnerList empManListnerList;
void CreateEmployeeEventNotify (CEmployee& employee) //Notify each listner of the event
{
EmployeeManagerListnerList::iterator iter;
for( iter = empManListnerList.begin(); iter != empManListnerList.end(); ++iter)
(*iter)->CreateEmployeeEvent(employee);
}
void ListEmployeesEventNotify (EmployeeList& employeeList);
};
class CUserInterface : public IEmployeeManagerListner
{
public:
void Initialize()
{
empManager.AddListner(dynamic_cast<IEmployeeManagerListner*>(this));
}
void GetEmployeeDetailEvent();
void UpdateUI();
private:
CEmployeeManager empManager;
virtual void CreateEmployeeEvent (CEmployee& employee) {}
virtual void ListEmployeesEvent (EmployeeList& employeeList) {}
};
I have used inheritance to implement the observer pattern. Inheritance immediately means - high coupling. Can the same be accomplished without using inheritance?
ChessMaster
June 12th, 2008, 03:48 AM
i have been pondering over the relation of employee manager with employee class.
Should it have a list of employees? or what kind of relation shd it have?
For now, the user of Employee Manager will maintain the list of employee(s) obtained by the manager, and let manager deal with only managing.
How do i make a decision on the same? on basis of what do i come to a conclusion?
code_carnage
June 12th, 2008, 05:59 AM
i have modified the design. now using the observer pattern.
I have implemented for only one layer, the next layer (WebService) i can implement in the same manner.
struct CEmployee;
class IEmployeeManagerListner;
typedef std::list<CEmployee> EmployeeList;
typedef std::list<IEmployeeManagerListner*> EmployeeManagerListnerList;
class CWebServiceGateway
{
void createObject(std::string request); //Used to create employee
void deleteObject(std::string request); //delete employee
void getObjects(std::string request); //get employee(s) details
//...
};
struct CEmployee
{
std::string m_Name;
int m_ID;
};
class IEmployeeManagerListner
{
public:
virtual void CreateEmployeeEvent (CEmployee& employee) = 0;
virtual void ListEmployeesEvent (EmployeeList& employeeList) = 0;
};
class CEmployeeManager
{
public:
void CreateEmployee (CEmployee& employee);
void ListEmployees (EmployeeList& employeeList);
void AddListner(const IEmployeeManagerListner *const newListner)
{
empManListnerList.push_back(newListner);
}
private:
EmployeeManagerListnerList empManListnerList;
void CreateEmployeeEventNotify (CEmployee& employee) //Notify each listner of the event
{
EmployeeManagerListnerList::iterator iter;
for( iter = empManListnerList.begin(); iter != empManListnerList.end(); ++iter)
(*iter)->CreateEmployeeEvent(employee);
}
void ListEmployeesEventNotify (EmployeeList& employeeList);
};
class CUserInterface : public IEmployeeManagerListner
{
public:
void Initialize()
{
empManager.AddListner(dynamic_cast<IEmployeeManagerListner*>(this));
}
void GetEmployeeDetailEvent();
void UpdateUI();
private:
CEmployeeManager empManager;
virtual void CreateEmployeeEvent (CEmployee& employee) {}
virtual void ListEmployeesEvent (EmployeeList& employeeList) {}
};
I have used inheritance to implement the observer pattern. Inheritance immediately means - high coupling. Can the same be accomplished without using inheritance?
Its absolutely fine that you have used inheritance. Infact technically you have used inheritance but in essence you have not because you are not inheriting any code from your base class but some pure virtual methods. In othe words you are programming to an interface. Which is ofcourse essential because every class which has to become listenere has to inherit from IEmployeeManagerListner.
So your Employee Manager does not have to know about the actual type of object to send the notification or regsiter that object.
Any object can be registered to the Employee Manager as long as it inherits from Listner interface which is IEmployeeManagerListner in your case..
Moreover, why have you used dynamic cast.
[code
empManager.AddListner(dynamic_cast<IEmployeeManagerListner*>(this));
[/code]
This is not only unnessessry but evil.
ChessMaster
June 17th, 2008, 02:35 AM
Firstly, thank you for all your responses.
Kindly excuse my disapperance, was buried in work, hence was unable to follow up the thread for a while.
I was wondering if there is an alternative to inheritance, if there are multiple ways to approach the same. It is very informative and helps in learning.
I still have one major task left...Error Handling or rather - error notification!
How do i inform users of classes of the errors. For example, the CWebServiceGateway class knows if there is a connection failure or something on the same line. When CEmployeeManager class uses the services of CWebServiceGateway class he is informed of the appropriate error. Now how do i map these errors such that it is informative enough to the user of the CEmployeeManager class (CUserInterface)?
code_carnage
June 17th, 2008, 03:12 AM
I was wondering if there is an alternative to inheritance, if there are multiple ways to approach the same. It is very informative and helps in learning.
If you want to implement observer pattern there is no alternative.
Moreover, its not inheritance for code reuse which end up giving tight coupling but here inheritance is used for progamming with interface and hence gives you loose coupling. If you dont use inheritance here you code will be tightly coupled because you wont be programming to an interface. Bottom line is there is other alternative..
I still have one major task left...Error Handling or rather - error notification!
How do i inform users of classes of the errors. For example, the CWebServiceGateway class knows if there is a connection failure or something on the same line. When CEmployeeManager class uses the services of CWebServiceGateway class he is informed of the appropriate error. Now how do i map these errors such that it is informative enough to the user of the CEmployeeManager class (CUserInterface)?
Error handling is a seperate subject. I guess that you dont alreay have any error handling mechanism in place.
I would never recommend observer pattern for error handling..:eek:
You can do one of these.
1. Keep a boolean variable in connect class when connection is broken set it to false else true. Check everytime for its value when you do some operation. If its false then call a global method which would fix the connection object.
2 Simply rely on throwing excpetion and gracefully exit by logging the error and dont try to fix the connection object.
3. Keep a singeton Error class that has the fecility to set the error text in the Error object . At hieghest level of your code mainly UI level clear the Error text what so ever in the error object. Do lower level operation and while doing so if you encounter a problem set that in Error object and return. Now at UI level see the Error obejct once again and see whether there is a text inside it or its clean.
If there is a text inside it.Log the text/Show the text in UI to the user and exit the application if the error can not be corrected.
There could be many such approaches it depends what suits you most..
ChessMaster
June 17th, 2008, 09:28 AM
I would never recommend observer pattern for error handling...
Well then, is there another pattern/approach that would help me solve the above problem?
If yes, what is it??
If no...then should not - any code that is written, be it the observer pattern or the jim carrey pattern :D, it must consider and should handle error scenarios.
In my above code - connection down was just an example. For instance, i could have other kinds of errors. Well, like assume calling a library function or winAPI or in my caseof the webservice response which could specify a particular error. So how do i go about to solve this? The singleton was something that seems reasonable. I was also wondering if i could do something what the winAPI does - like GetLastError.
Does anyone has better ideas or better approaches for the same?
Graham
June 17th, 2008, 09:44 AM
There's nothing wrong with using Observer to convey information such as "connection lost" or suchlike. I wouldn't use it for "illegal parameter value" or "ran out of memory", though. assert() was devised for the first one and exceptions for the second.
ChessMaster
June 18th, 2008, 12:51 AM
Earlier in this thread i had mentioned about a couple of design issues.
i was lookin forward to reading comments on the same
i have been pondering over the relation of employee manager with employee class.
Should it have a list of employees? or what kind of relation shd it have?
For now, the user of Employee Manager will maintain the list of employee(s) obtained by the manager, and let manager deal with only managing.
How do i make a decision on the same? on basis of what do i come to a conclusion?
Today at work, bunch of my 'friends' were gunning for my head mentioning this is not really object oriented. In my design, the EmployeeManager class manages the employee. Their point was that, EmployeeManager is not an by itself object (an object should have properties and methods to manipulate the same), since it has GetEmployee which is a specific employee and such operations like Create...Delete...along with these there is GetEmployeeList which does'nt belong here.
I would like to know what the gurus :cool:, here think about the same :)
Graham
June 18th, 2008, 04:01 AM
They're talking drivel.
Ask them exactly why an object should have properties. Why is it "not object-oriented" to have a controller object that organises and controls the interactions of other objects?
codeguru.com
Copyright Internet.com Inc., All Rights Reserved.