Design Question: Which is Better practice?
I have 3 different web servers which handle user data (username/passwd/email/etc.). I have 3 different web service calls respectively, so I've created 3 different classes which calls for the same information (getUsername
, setUsername
, getEmail
, setEmail
, etc.). From the main class I instantiate each webservice-call objects and when I have a request for 开发者_开发百科a new username, password I call the createUsername()
method of each class (provisioning the data).
Do you have any suggestions on how to apply a design pattern for this problem? I thought of making a class which will have a method createUsername() {}
and in this I would call each of the webservice-classes and store each result in a predefined array. Does anyone have any suggestion or a better practice?
currently i have:
class webservice1calls {
function createUser($username, $password) {}
function deleteUser($username, $password) {}
function createGroup($groupname) {}
function deleteGroup($groupname) {}
}
class webService2calls {
function createUser($username, $password) {} //different implementation
function deleteUser($username, $password) {} //different implementation
function createGroup($groupname) {} //different implementation
function deleteGroup($groupname) {} //different implementation
}
class webService3calls {
function createUser($username, $password) {} //different implementation
function deleteUser($username, $password) {} //different implementation
function createGroup($groupname) {} //different implementation
function deleteGroup($groupname) {} //different implementation
}
//My "like a proxy" class:
class webServiceCalls {
function createUser($username, $password) {
$ws1 = new webService1calls();
$ws2 = new webService2calls();
$ws3 = new webService3calls();
$res1 = $ws1->createUser($username, $password);
$res2 = $ws2->createUser($username, $password);
$res3 = $ws3->createUser($username, $password);
// return result depending $res1,$res2 and $res3 values
}
//and the call is done from another class somewhat like this:
class doThings {
function run() {
$ws = new webServiceCalls();
$ws_res = $ws->createUser();
}
}
I thought that the above representation would help you understand the current
design (and maybe a better understanding of the problem.
thanks!Eep! Firstly, since these are so similar, they should share a common base class or use an interface:
interface WebService {
function createUser($username, $password);
function deleteUser($username, $password);
function createGroup($groupname);
function deleteGroup($groupname);
}
class MyService implements WebService {
function createUser($username, $password) {}
function deleteUser($username, $password) {}
function createGroup($groupname) {}
function deleteGroup($groupname) {}
}
Secondly, I hope your services aren't actually called 1,2,3. If they are, that suggests to me that maybe you should be using some form of an array.
I don't like your idea of a "proxy" class. Are you always using all 3 services, or is this some sort of library where you just include the service you need? You haven't provided enough info about what you're actually trying to accomplish.
I like the idea of keeping each server's implementation in a separate class, and I also like Mark's idea of utilizing an interface. I'm also fond of your idea of a proxy class, but not in the form that you presented. I would create a class that acts as a pool of sorts. Something like this:
class WebServicePool implements WebService {
private $webServices = array();
public function registerWebService($service) {
if($service instanceof WebService)
$this->webServices[] = $service;
}
function createUser($username, $password) {
foreach($this->webServices as $service)
$service->createUser($username, $password);
}
// ...
}
You could also use magic methods to proxy this functionality:
class WebServicePool {
private $webServices = array();
public function registerWebService($service) {
if($service instanceof WebService)
$this->webServices[] = $service;
}
function __call($name, $arguments) {
foreach($this->webServices as $service)
call_user_func_array(array($service, $name), $arguments);
}
}
That way, if you add more functions to your interface, you won't need to update your pool class. Hope this helps!
What do you think about a Model - ModelMapper arch? Zend Framework uses this approach. You could have possibily the following classes: (silly naming convention for better understanding)
Model_User
Mapper_User_Email
Mapper_User_Name
Mapper_User_Password
And the individual mappers read the needed data, the 3rd party class only calls Model_User->getName()
Edit: Example usage:
//simple code:
$user = new Model_User();
echo "Your name is: " . $user->getName();
//Model_User:
public function getName() {
if($this->_name = null) {
$this->getNameMapper()->getName($this);
//getNameMapper() returns a Mapper_User_Name object
}
return $this->getName();
}
//Mapper_User_Name:
public function getName($user) {
$name = "john"; /*magic here, the class communicate with the service that holds names*/
$user->setName($name);
}
Example only, the getters and setters could be more defensive.
I would take a completely different approach. A REST interface would be perfect for what you're trying to do, which are the standard CRUD commands.
精彩评论