views:

116

answers:

3

I want to create a voting system, where multiple domain objects can be voted on:

  • a calendar event
  • a comment
  • a user

So I figured I would create a Voteable interface for these items:

interface Voteable
{
    public function vote( User $user, $value );
}

I thought this vote method would proxy a repository method, something like:

class VotingRepository
{
    public function castVote( Voteable $item, User $user, $value )
    {
        // save the these values, along with the value
        $itemId = $item->getId();
        $userId = $user->getId();

    }
}

For now, the repository will be a database. This database will have linking tables for each type of vote:

  • eventVote
  • commentVote
  • userVote

So, this essentially means that each domain object needs another table to cast the votes to. Would this be a good candidate for a factory? A VotingRepositoryFactory in this case? In other words something like:

class VotingRepositoryFactory
{
    createVotingRepository( $type )
    {
        switch( $type )
        {
            case 'event':
                // create a voting repository with EventVote table
                return new VotingRepository( new EventVoteTable() );
            case 'comment':
                // create a voting repository with CommentVote table
                return new VotingRepository( new CommentVoteTable() );
            case 'user':
                // create a voting repository with UserVote table
                return new VotingRepository( new UserVoteTable() );
        }
    }
}

Then, tying it all together, from within the domain objects (comment in this case for example), I would look something like this:

class Comment implements Voteable
{
    public function construct()
    {
        $this->_repository = VotingRepositoryFactory::createVotingRepository( 'comment' );
    }

    public function vote( User $user, $value )
    {
        $this->_repository->castVote( $this, $user, $value );
    }
}

Does this make sense?

+2  A: 

Yep, it does.

:]

Adam Kiss
What?! No if's , and's, or but's...??? Am I really starting to get the hang of this after all? Woohoo! :-D
fireeyedboy
Hmm.. Sorry but you have answered your question with a perfect answer
streetparade
Well, then to the both of you: thank you both for the reassurance.
fireeyedboy
+1  A: 

Oh Yes it makes. +1

streetparade
+3  A: 

yes both the repository and the factory make sense.

a few comments about the factory:

i'd remove the switch ($type) and create methods for each type of Votable object. so instead of

VotingRepositoryFactory::createVotingRepository( 'comment' );

i'd prefer

VotingRepositoryFactory::createCommentVotingRepository();

the reason being that it's easy to forget to add a new case to the switch, while (i'm not sure about php, but) compiled languages will tell you when a called method is missing. also remembering what strings you can send into the factory method as $type is hard, while most intelligent IDEs will tell you what methods exist on a class/object.

another idea would be to add a singleton that could be called like VotingRepositoryFactory::Instance->createCommentVotingRepository();. the "Instance" could then be a DatabaseVotingRepositoryFactory or a FakeVotingRepositoryFactory (for unit testing) or any other implementation of a VotingRepositoryFactory. that way you could easily replace the implementation of the VotingRepositoryFactory if you want to write unit tests or switch to some other storage system.

just a few ideas..

stmax
+1 That is some great additional information. Thank you. So, let me see if I get this straight: in other words you are saying that the `getInstance()` would kind of be like a factory as well? That returns another factory based on some config for instance? Is this what is referred to as an abstract factory by any chance?
fireeyedboy
yes, the object returned by getInstance() would be an abstract factory. you can use some kind of config file to tell what type of factory it should create. sometimes i even just hard code it (_instance = new ...). it still makes it very easy to replace once you have to (one line of code). once more and more singletons start to pop up in your application, you might also want to take a look at the "ServiceLocator" pattern or some kind of IoC-containers.. that way you can configure all your singletons (and much more) in a central place.
stmax