Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

An assignment in my software engineering class is to design an application which can play different forms a particular game. The game in question is Mancala, some of these games are called Wari or Kalah. These games differ in some aspects but for my question it's only important to know that the games could differ in the following:

  • The way in which the result of a move is handled
  • The way in which the end of the game is determined
  • The way in which the winner is determined

The first thing that came to my mind to design this was to use the strategy pattern, I have a variation in algorithms (the actual rules of the game). The design could look like this: enter image description here

I then thought to myself that in the game of Mancala and Wari the way the winner is determined is exactly the same and the code would be duplicated. I don't think this is by definition a violation of the 'one rule, one place' or DRY principle seeing as a change in rules for Mancala wouldn't automatically mean that rule should be changed in Wari as well. Nevertheless from the feedback I got from my professor I got the impression to find a different design.

I then came up with this: enter image description here

Each game (Mancala, Wari, Kalah, ...) would just have attribute of the type of each rule's interface, i.e. WinnerDeterminer and if there's a Mancala 2.0 version which is the same as Mancala 1.0 except for how the winner is determined it can just use the Mancala versions.

I think the implementation of these rules as a strategy pattern is certainly valid. But the real problem comes when I want to design it further.

In reading about the template method pattern I immediately thought it could be applied to this problem. The actions that are done when a user makes a move are always the same, and in the same order, namely:

  • deposit stones in holes (this is the same for all games, so would be implemented in the template method itself)
  • determine the result of the move
  • determine if the game has finished because of the previous move
  • if the game has finished, determine who has won

Those three last steps are all in my strategy pattern described above. I'm having a lot of trouble combining these two. One possible solution I found would be to abandon the strategy pattern and do the following: enter image description here

I don't really see the design difference between the strategy pattern and this? But I am certain I need to use a template method (although I was just as sure about having to use a strategy pattern).

I also can't determine who would be responsible for creating the TurnTemplate object, whereas with the strategy pattern I feel I have families of objects (the three rules) which I could easily create using an abstract factory pattern. I would then have a MancalaRuleFactory, WariRuleFactory, etc. and they would create the correct instances of the rules and hand me back a RuleSet object.

Let's say that I use the strategy + abstract factory pattern and I have a RuleSet object which has algorithms for the three rules in it. The only way I feel I can still use the template method pattern with this is to pass this RuleSet object to my TurnTemplate. The 'problem' that then surfaces is that I would never need my concrete implementations of the TurnTemplate, these classes would become obsolete. In my protected methods in the TurnTemplate I could just call ruleSet.determineWinner(). As a consequence, the TurnTemplate class would no longer be abstract but would have to become concrete, is it then still a template method pattern?

To summarize, am I thinking in the right way or am I missing something easy? If I'm on the right track, how do I combine a strategy pattern and a template method pattern?

share|improve this question
1  
I'd say your thinking is pretty much spot on. If the feedback you get from your professor doesn't validate that, ask him/her to point out the flaws, or give a hint of what (s)he is after in the answer. Stop trying to read minds. Assuming stuff about what your professor (and later your users) want is possibly the worst you can do. –  Marjan Venema Oct 28 '12 at 8:11
add comment

4 Answers 4

up vote 4 down vote accepted

After looking at your designs, both your first and third iterations appear to be more elegant designs. However, you mention that you're a student and your professor gave you some feedback. Without knowing exactly what your assignment or the purpose of the class is or more information about what your professor suggested, I would take anything I say below with a grain of salt.

In your first design, you declare your RuleInterface to be an interface that defines how to handle each player's turn, how to determine if the game is over, and how to determine a winner after the game ends. It seems like that's a valid interface to a family of games that experiences variation. However, depending on the games, you might have duplicated code. I'd agree that the flexibility to change the rules of one game is a good thing, but I'd also argue that code duplication is terrible for defects. If you copy/paste defective code between implementations and one has a bug in it, you now have multiple bugs that need to be fixed in different locations. If you rewrite the implementations at different times, you could introduce defects in different locations. Neither of those is desirable.

Your second design seems rather complex, with a deep inheritance tree. At least, it's deeper than I would expect for solving this type of problem. You're also starting to break up implementation details into other classes. Ultimately, you are modeling and implementing a game. This might be an interesting approach if you were required mix-and-match your rules for determining the results of a move, the end of the game, and a winner, that doesn't seem to be in the requirements that you've mentioned. Your games are well defined sets of rules, and I'd try to encapsulate the games as much as I can into separate entities.

Your third design is one that I like the best. My only concern is that it's not at the right level of abstraction. Right now, you appear to be modeling a turn. I would recommend considering designing the game. Consider that you have players who are making moves on some kind of board, using stones. Your game requires these actors to be present. From there, your algorithm is not doTurn() but playGame(), which goes from the initial move to the final move, after which it terminates. After every player's move, it adjusts the state of the game, determines if the game is in a final state, and if it is, determines the winner.

I would recommend taking closer looks at your first and third designs and working with them. It might also help to think in terms of prototypes. What would the clients that use these interfaces look like? Does one design approach make more sense for implementing a client that's actually going to instantiate a game and play the game? You need to realize what it's interacting with. In your particular case, it's the Game class, and any other associated elements - you can't design in isolation.


Since you mention you're a student, I'd like to share a few things from a time when I was the TA for a software design course:

  • Patterns are simply a way of capturing things that have worked in the past, but abstracting them to a point where they can be used in other designs. Each catalog of design patterns gives a name to a pattern, explains its intentions and where it can be used, and situations where it would ultimately constrain your design.
  • Design comes with experience. The best way to get good at design isn't to simply focus on the modeling aspects, but realize what goes into the implementation of that model. The most elegant design is useful if it can't easily be implemented or it doesn't fit into the larger design of the system or with other systems.
  • Very few designs are "right" or "wrong". As long as the design fulfills the requirements of the system, it can't be wrong. Once there's a mapping from each requirement into some representation of how the system is going to meet that requirement, the design can't be wrong. It's only a qualitative at this point about concepts such as flexibility or reusability or testability or maintainability.
share|improve this answer
    
Thanks for the great advice, especially your point about the fact that it was at the wrong level of abstraction. I've changed it now to a GameTemplate which does feel a lot better. It also allows me to combine a factory method to initialize players, the board, etc. –  Mekswoll Oct 28 '12 at 19:22
add comment

Let's get down to brass tacks. There is absolutely no need for any Game interface, no design patterns, no abstract classes, and no UML.

If you have a reasonable amount of support classes, like UI, simulation, and whatever, then basically all of your non-game-logic-specific code is re-used anyway. Moreover, your user does not change his game dynamically. You do not flip at 30Hz between games. You play one game for about half an hour. So your "dynamic" polymorphism is not actually dynamic at all. It's rather static.

So the sensible way to go here is to use a generic functional abstraction, like C#'s Action or C++'s std::function, create one Mancala, one Wari, and one Kalah class, and go from there.

std::unordered_map<std::string, std::function<void()>> games = {
    { "Kalah", [] { return Kalah(); } },
    { "Mancala", [] { return Mancala(); } },
    { "Wari", [] { return Wari(); } }
};
void play() {
    std::function<void()> f;
    f = games[GetChoiceFromUI()];
    f();
    if (PlayAgain()) return play();
}
int main() {
    play();
}

Done.

You don't call Games. Games call you.

share|improve this answer
2  
I don't see how this is helpful at all. The person asking this question is a student. He's explicitly asking about design principles and the interactions between two design patterns. Saying that there isn't a need for design patterns or UML could be true in some instances in industry, but thinking about design models, design patterns, and UML could be the point of the exercise being asked about. –  Thomas Owens Oct 27 '12 at 22:39
3  
There's nothing to say about them, because there's nowhere that they apply. There's no point spending your time thinking about how you would completely cock up design using design patterns, unless you intend it to be a lesson on how not to use them. –  DeadMG Oct 27 '12 at 22:43
4  
There's a worrying/annoying trend in SoftDev where the design patterns used are considered more important than just solving the problem. There is such a thing as over-engineering. –  James Oct 28 '12 at 0:07
2  
@DeadMG: while both of you are essentially right, in OP's case the problem is passing the exam, and the solution to that problem is to use design patterns and UML. No matter how right we are, if his professor doesn't agree with his solutions, he won't pass. –  Goran Jovic Oct 28 '12 at 14:23
    
My whole life I've always thought it was "brass tax"... Wow, "brass tacks" makes way more sense. lol –  mmmshuddup Oct 29 '12 at 9:40
add comment

If you're being distracted by design patterns my advice to you would be to prototype the game first then patterns should just jump out at you. I don't think it's really possible or advisable to try to design a system perfectly first and then implement it (in a similar way I find it perplexing when people try to write entire programs first and then compile, rather then doing it bit by bit.) The trouble is that it's unlikely you'll think of every scenario your logic will have to deal with, and during the implementation phase you'll either lose all hope or try to stick to your original flawed design and introduce hacks, or even worse deliver nothing at all.

share|improve this answer
2  
While in general I agree with you, this isn't really a answer that solves the OP's problem. "Don't do that" is an answer, but a rather poor one if it doesn't provide a viable alternative. –  Yannis Rizos Oct 28 '12 at 4:30
    
@YannisRizos And while I agree with you as well, I still think he gave sound advice (or insight if advice isn't the right word). For that reason, +1. Even though, yes it's not technically a very helpful answer. –  mmmshuddup Oct 29 '12 at 9:38
add comment

Your confusion is justified. The thing is that patterns aren't mutually exclusive.

Template method is the basis for a bunch of other patterns, such as Strategy and State. Essentially, the Strategy interface contains one or more template methods, each requiring all objects implementing a strategy to have (at least) something like a doAction() method. This allows the strategies to be substituted for one another.

In Java, an interface is nothing but a set of template methods. Likewise, any abstract method is essentially a template method. This pattern (among others) was well known to the designers of the language, so they built it in.

@ThomasOwens offers excellent advice on approaching your particular problem.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.