Re: Question about OO design

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



# cparker@xxxxxxxxxxxx / 2007-04-09 15:29:01 -0700:
> (I'm dealing with PHP4.)
> 
> class User
> {
> 	var id;
> 	var name;
> 	var email;
> 	var balance;
> 	var accrual;
> 	var is_manager;
> 
> 	function User($user_id)
> 	{
> 		$this->id = $user_id;
> 		$this->name = get_name();
> 		// ...
> 		$this->accrual = get_accrual();
> 	}
> 
> 	function get_name()
> 	{
> 		// get name from db
> 		$sql = "...";
> 
> 		$db =& DB::singleton();
> 		$db->execute($sql);
> 	}

That static call on DB makes User tightly coupled to DB.  This class
won't work without the other.  Aggravated by the multiple calls.
Jochem cut the number down to 1 by doing the work in the constructor,
but that doesn't remove the dependency, just makes it easier to remove
eventually.  The usual technique is to pass the database connection
to the constructor:

class User
{
    function User($data_source, $user_id)
    {
        $this->ds = $data_source;
        $this->id = $user_id;
        $this->_fetch_data();
    }
    var $ds, $id;
    function _fetch_data()
    {
        $this->ds->execute(...);
    }
}

Now, the User class is completely independent of the DB class. You can
use User with any other class that has the same interface as DB.
Of course, the more abstraction you provide, the more versatility you
get, so you definitely don't want to have any SQL embedded in the
business logic or classes as generic as User.  I'll leave the issue of
abstracting away data acquisition as an exercise for the reader.

What about the places where you instantiate the User class?  You would
now need to change every

new User($id)

to at least

new User($dbconn, $id)

You can (and should) solve that by encapsulating the User instantiation.
The tight coupling problem applies to all classes, including User.
The industry standard technique to solve this is to use a creation or
factory method:

class UserFactory
{
    function UserFactory($dbconn)
    {
        $this->dbconn = $dbconn;
    }
    var $dbconn;
    function create($id)
    {
        return new User($this->dbconn, $id);
    }
}

$uf = new UserFactory($dbconn);
...
$user = $uf->create($id);

And to prevent creating multiple instances of a single user (but you're
screwed in PHP anyway):

# NOTE: not bothering with references at all
class Users
{
    function Users($factory)
    {
        $this->factory = $factory;
    }
    var $factory;
    var $users = array();
    function get($id)
    {
        if (!isset($this->users[$id])) {
            $this->users[$id] = $this->factory->create($id);
        }
        return $this->users[$id];
    }
}

$users = new Users($factory);
...
$user = $users->get($id);

The classes follow two simple principles: Don't Repeat Yourself and
Single Responsibility Principle (DRY, SRP).  Sticking to them yields
tremendous benefits in my experience, as does No Hardwiring, Please.

Recommended reading: Design Patterns, Gamma et al.; Test-Driven
Development by Example, Beck; Patterns of Enterprise Application
Architecture, Fowler, C++ User's Journal archives.

Also, did I mention that Singleton has turned a bit sour since its
publication in Design Patterns, and is now considered an antipattern?
Quoting one of the authors of the book:

: It is a bad sign that the only pattern you mentioned was Singleton.
: This shows you don't understand how to construct GUIs very well.
: Singleton is a weak pattern, and whenever people start with
: Singleton, it is a sign of a bad design.
:    
: -Ralph Johnson

-- 
How many Vietnam vets does it take to screw in a light bulb?
You don't know, man.  You don't KNOW.
Cause you weren't THERE.             http://bash.org/?255991

-- 
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php


[Index of Archives]     [PHP Home]     [Apache Users]     [PHP on Windows]     [Kernel Newbies]     [PHP Install]     [PHP Classes]     [Pear]     [Postgresql]     [Postgresql PHP]     [PHP on Windows]     [PHP Database Programming]     [PHP SOAP]

  Powered by Linux