What design pattern would you use in the following scenario...

59 views
Skip to first unread message

Mohamad El-Husseini

unread,
Jul 11, 2011, 5:51:12 PM7/11/11
to coldfu...@googlegroups.com
Say you were working on an app that mirrored functionality in StackOverFlow, in particular, their voting system.

According to their schema they have 16 vote types, all stored in the same table.

Vote types Up, Down, Accept, Delete, and Undelete influence reputation for recipients and voters, as well as denormalized columns in the posts table.

Link, Close, and Reopen votes trigger notifications. Other vote types have no behavior.

With that in mind, what type of strategy would you use to implement such a system, and why?

It's possible to have one DAO, but you would need 16 if statements to determine the behaviour based on the vote type... 

I'm curious to see how people approach this from an OOP perspective...

Sean Corfield

unread,
Jul 11, 2011, 6:38:34 PM7/11/11
to coldfu...@googlegroups.com
I'd probably use the Strategy Pattern and a Factory to map from vote
type (string) to the actual strategy.

(That said, you're providing very minimal information and all design
patterns have trade offs so choosing them needs to be based on pros
_and_ cons)

Mohamad El-Husseini

unread,
Jul 11, 2011, 7:49:26 PM7/11/11
to coldfu...@googlegroups.com
Sean, thanks for sharing. I'll provide some more detail: For my project, I decided to clone the SO engine. I first wrote it in Wheels, now I am writing it in FW/1 and Hibernate.

My current system handles 4 voting types (up, down, accept, favourite) and relies on inheritance. You can see it in action here: http://swop-com-br.securec19.ezhostingserver.com/gamers/index.cfm

I have a base vote class with common functionality. Each specialized vote object has callbacks that handle its behaviours.

Favourite.cfc, for example, has an afterDelete() and afterCreate() callbacks that call updatePostFavouriteCount() accordingly.

VoteUp.cfc, VoteDown.cfc, and VoteAccept.cfc also employ callbacks to update a post's score, and the reputation of author and voter.

This works well for 4 types of votes. But now I want to introduce VoteFlag.cfc, VoteClose.cfc, and VoteReopen.cfc; none of those vote types will impact reputation. After a certain count is reached, VoteClose.cfc/VoteReopen.cfc will prevent a question from being answered/commented on.

If I weren't trying this in a new framework, I would probably just add the new vote sub-classes and use callbacks. But since I'm switching tools, I want to know people's thoughts on doing this.

Sean Corfield

unread,
Jul 11, 2011, 9:20:25 PM7/11/11
to coldfu...@googlegroups.com
On Mon, Jul 11, 2011 at 4:49 PM, Mohamad El-Husseini
<hussei...@gmail.com> wrote:
> My current system handles 4 voting types (up, down, accept, favourite) and
> relies on inheritance.

I would decouple the behavior from the inheritance much as I suggested
with Strategy and Factory. It's a common mistake in OO to overuse
inheritance.

I'll be interested to hear what others have to say about this :)
--
Sean A Corfield -- (904) 302-SEAN
An Architect's View -- http://corfield.org/
World Singles, LLC. -- http://worldsingles.com/
Railo Technologies, Inc. -- http://www.getrailo.com/

"Perfection is the enemy of the good."
-- Gustave Flaubert, French realist novelist (1821-1880)

Mohamad El-Husseini

unread,
Jul 13, 2011, 10:44:58 AM7/13/11
to coldfu...@googlegroups.com
Sean,

I started giving this a bit more thought, and I realized that those behaviours (editing reputation for author and vote, post score, etc...) should not belong to the vote. Shouldn't they belong to VoteService.cfc?

transaction {
   // new vote
   vote = entityNew("voteDown");
   vote.userId = voter.getId();
   vote.postId = post.getId();

   // edit voter and author and post
   voter.editRep(value);
   author.editRep(value);
   post.editScore();
}

Editing the post, the voter, and the author aren't behaviours of the vote, are they? They're just consequences. That said, why bother with any type of pattern, instead of just using inheritance. Or should those behaviours belong in a model and not a service?

Am I making sense?

Sean Corfield

unread,
Jul 13, 2011, 9:25:03 PM7/13/11
to coldfu...@googlegroups.com
On Wed, Jul 13, 2011 at 7:44 AM, Mohamad El-Husseini
<hussei...@gmail.com> wrote:
> Editing the post, the voter, and the author aren't behaviours of the vote,
> are they? They're just consequences. That said, why bother with any type of
> pattern, instead of just using inheritance. Or should those behaviours
> belong in a model and not a service?
> Am I making sense?

Not really. You're starting from a position where you already have an
object structure in place and assuming it's right ("Shouldn't they
belong to VoteService.cfc?").

Please at least go read the Strategy and Factory Method patterns so
you can see what I'm suggesting...

Judith Barnett

unread,
Jul 13, 2011, 10:10:20 PM7/13/11
to coldfu...@googlegroups.com
Any links to good info on this?

On Wed, Jul 13, 2011 at 6:25 PM, Sean Corfield <seanco...@gmail.com> wrote:

>
> Please at least go read the Strategy and Factory Method patterns so

> you can see what I'm suggesting...\

Alex Sante

unread,
Jul 13, 2011, 10:20:50 PM7/13/11
to coldfu...@googlegroups.com
http://sourcemaking.com/design_patterns/strategy


--
You received this message because you are subscribed to the Google Groups "Object-Oriented Programming in ColdFusion" group.
To post to this group, send email to coldfu...@googlegroups.com.
To unsubscribe from this group, send email to coldfusionoo...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/coldfusionoo?hl=en.


Sean Corfield

unread,
Jul 13, 2011, 10:56:23 PM7/13/11
to coldfu...@googlegroups.com
On Wed, Jul 13, 2011 at 7:10 PM, Judith Barnett <jmba...@gmail.com> wrote:
> Any links to good info on this?

The best reference is the "Gang of Four" book: Design Patterns by
Gamma, Helm, Johnson, Vlissides. I've heard the Head First Design
Patterns book is quite good too.

Mohamad El-Husseini

unread,
Jul 13, 2011, 11:06:55 PM7/13/11
to coldfu...@googlegroups.com
Fair enough, but I still can't wrap my head around implementation. I guess this is because I'm a beginner and theory seldom makes sense to me until I start implementing it and learn the hard way.

Every already listened to 10 or more presentations on design patterns, a couple on the Strategy pattern, and read a bunch of stuff. I just finished reading OOP in CF to boot. I've always heard "encapsulation."

This lead me to believe that only the objects themselves should have methods to modify them. This is why the most natural solution seemed a VoteService.cfc that just handles all the business logic.

I can't see why VoteDown.cfc or VoteUp.cfc should be responsible for doing user.setReputation() or post.setScore()... especially when such tasks have to be performed in a transaction.

I'm not saying you're not right. I know you are. I'm just saying I don't understand why, and reading a ton of theoretical stuff as well as listening to presentations hasn't helped much in visualizing the solution.

I tend to go with what seems natural. It's often wrong, because what seems natural is proportional to my level of experience, which is not much. It's just frustrating some times to list to a talk on Strategy Pattern that uses ducks and duck behaviours for an example. If the ducks interacted with other objects, at the very least I would have had something to latch on to.

Mohamad El-Husseini

unread,
Jul 13, 2011, 11:11:41 PM7/13/11
to coldfu...@googlegroups.com
I guess what I wanted to say above is that I am reading and I'm not being lazy at all. I just can't connect the dots between theory and practice.

I can't seem to translate "interface --> implementation one, implementation two" or Duck, quake(), fly(), etc... into VoteService, UserService, User, Vote, and Post CFCs and so on.

Sean Corfield

unread,
Jul 14, 2011, 12:49:50 AM7/14/11
to coldfu...@googlegroups.com
On Wed, Jul 13, 2011 at 8:06 PM, Mohamad El-Husseini
<hussei...@gmail.com> wrote:
> Fair enough, but I still can't wrap my head around implementation. I guess
> this is because I'm a beginner and theory seldom makes sense to me until I
> start implementing it and learn the hard way.

I think you're trying to run before you can walk. Design Patterns
really only make sense when you have a fair bit of OO experience and
you've run into the problems that they can help you solve - and you
have enough experience to recognize those problems.

I think you just need to focus on implementing solutions to your
problems without worrying about design patterns or the "best" way to
do things.

OO is hard. You can't "get it" from books alone and you can't "do it
right" first time - it simply isn't possible (unless you are some sort
of savant that was born with a universal understanding of modeling the
world in software terms).

> This lead me to believe that only the objects themselves should have methods
> to modify them. This is why the most natural solution seemed a
> VoteService.cfc that just handles all the business logic.

But that's the _opposite_ of a an object with methods that mutate.
Services don't have state so any methods are by definition going to
operate on _other_ objects.

The vote knows who is voting, and what / who is being voted on. The
strategy would know _what_ to do and the vote would pass the
appropriate actors to the strategy.

I think you're implementing the behaviors (strategies) as methods in
the service - or as conditional behavior within the service? That's
what I'm suggesting you abstract out - and remove the service
altogether. The strategy then becomes an attribute of the specific
vote instances, supplied by the factory method that knows how to
create specific vote instances.

My advice to you is probably going to sound a bit confusing:

Keep doing exactly what you're doing. Don't worry about patterns,
don't worry about best practices. Just do your own thing.

When you start to find pain points in what you're doing, read the
design patterns book. Keep reading it until you start to connect the
Context of the patterns to your problem and recognize the Pressures in
those patterns.

In other words, until you are experiencing pain - and can connect that
to specifics in the patterns - you don't need patterns.

Sean Corfield

unread,
Jul 14, 2011, 12:51:14 AM7/14/11
to coldfu...@googlegroups.com
On Wed, Jul 13, 2011 at 8:11 PM, Mohamad El-Husseini
<hussei...@gmail.com> wrote:
> I can't seem to translate "interface --> implementation one, implementation
> two" or Duck, quake(), fly(), etc... into VoteService, UserService, User,
> Vote, and Post CFCs and so on.

I think you're looking at patterns as code? That's not the right
approach. Patterns aren't code, they're concepts and templates for
design. Hopefully my other answer will help more...

Mohamad El-Husseini

unread,
Jul 18, 2011, 10:11:43 AM7/18/11
to coldfu...@googlegroups.com
I think you are right on both counts. I am looking at patterns as code. And I am trying to run before I can walk. I'll take your advice and go with baby steps until it becomes obvious where and why I need patterns. The whole point of this exercise is to learn, anyway.

Thanks for the input.

Sean Corfield

unread,
Jul 18, 2011, 2:22:40 PM7/18/11
to coldfu...@googlegroups.com
On Mon, Jul 18, 2011 at 7:11 AM, Mohamad El-Husseini
<hussei...@gmail.com> wrote:
> I think you are right on both counts. I am looking at patterns as code. And
> I am trying to run before I can walk.

What might help is to take the Gang of Four patterns book and read
each pattern - without looking at the Implementation or Sample Code
sections at all, just focusing on the pattern motivation,
applicability and consequences (that's one of the most important part:
the trade offs you make by using a pattern).

Only once you truly understand the pattern itself, can you see whether
it might help or hinder your particular problem / solution. Don't
expect that understanding to come quickly, tho'...

It's important to remember that these patterns were grown organically
out of lots of software experience and each pattern can have multiple
implementations that may also look very different in each language. I
used to give a talk on Design Patterns in CFML where I showed how
certain core patterns are trivial in CFML but extremely hard in Java
(Singleton, for example). I urged folks not to follow the pattern
implementations because they'd look different in CFML and if you're
not careful, you'll end up with Java-in-CFML or C++-in-CFML which is
not a good idea. At the time, I suggested folks look to Ruby for
inspiration rather than Java (although Ruby's metaprogramming
capabilities far outstrip CFML). In general, Java is a very poor model
for expanding your OO skills, esp. when you work with CFML for a
living. Ruby and Python are better models (dynamic scripting
languages) but those communities don't tend to worry much about design
patterns (possibly because they're not needed as much or they're
already baked into some of their common idioms?). Robert C. Martin
calls Ruby and Python "Smalltalk in C clothing" which is a pretty good
way to think of it (in the context of the GoF book having examples in
Smalltalk).

The Clojure community, for example, doesn't pay much attention to
design patterns. The question came up on the main mailing list one day
and it was pointed out that several common design patterns are either
inherent to the way people normally write Clojure code or the
implementation is so trivial as to be almost non-existent. In other
words, many of the patterns have already been internalized and so
folks don't need to agonize over whether to "apply" a design pattern
to their code.

Reply all
Reply to author
Forward
0 new messages