Stijn Heylen
Stijn Heylen

Reputation: 183

What design pattern should I use?

I have a studentadministration application. Now I have to implement a new part of this application that gives advise (in the style of a text) depending on the grades of the student. So we have 1 "algorithm" and 4(for the moment) different texts(variations) as output).

What is the best pattern in this case? I personally think about using the bridge pattern so that I can put the algorithm in the abstraction class and put the different texts as concrete implementors.

Upvotes: 0

Views: 158

Answers (2)

cwharris
cwharris

Reputation: 18125

I think you're over engineering this.

This is a pretty simple search algorithm problem. Your domain consists of Students (who want advice), Pieces of Advice (who contain knowledge), and a Provider of some kind, which will contain a search algorithm to help the student find advice.

Using the following, I can simply change the search algorithm at any time to suit my needs. I can either create an entirely new search, or modify the one I already have. In addition, I could create a search that works off of a database instead of a list of advice. I can add new criteria by updating my StudentAdvice model and searching for that advice within the provider (these are two distinct changes, so it does not violate the Open/Closed principle).

class Program
{
    static void Main(string[] args)
    {
        var advices = new[]
        {
            new StudentAdvice{ Grade = 60, Advice = "Talk to your professor." },
            new StudentAdvice{ Grade = 70, Advice = "Spend more time studing." },
            new StudentAdvice{ Grade = 80, Advice = "Spend even more time studing." },
            new StudentAdvice{ Grade = 90, Advice = "You're doing great, almost there!" },
            new StudentAdvice{ Grade = 100, Advice = "Perfect!" },
        };

        IStudentAdviceProvider adviceProvider = new GradeBasedAdviceProvider(advices);

        var student = new Student { Name = "Jim", Grade = 80 };

        foreach(var advice in adviceProvider.GetAdvice(student))
        {
            Console.WriteLine(advice.Advice);
        }
    }
}

public interface IStudentAdviceProvider
{
    IEnumerable<StudentAdvice> GetAdvice(Student student);
}

public class GradeBasedAdviceProvider : IStudentAdviceProvider
{
    private readonly IEnumerable<StudentAdvice> advices;

    public GradeBasedAdviceProvider(IEnumerable<StudentAdvice> advices)
    {
        this.advices = advices;
    }

    public IEnumerable<StudentAdvice> GetAdvice(Student student)
    {
        // Advice Selection Algorithm
        return advices.Where(advice => student.Grade <= advice.Grade).Take(1).ToList();
    }
}

public class Student
{
    public string Name { get; set; }
    public int Grade { get; set; }
}

public class StudentAdvice
{
    public int Grade { get; set; }
    public string Advice { get; set; }
}

At it's core, this could be used as a strategy pattern. However, I started with the domain, and the pattern emerged itself. Picking patterns first codes you into corners.

Learning design patterns gives us a bunch of tools to use. Learning SOLID design principles allows us to realize when those tools should be used. The following site has some great resources related to OOD.

http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod

Upvotes: 4

Vikk
Vikk

Reputation: 3363

Seems to me that template method pattern would be the best choice. You have an algorithm in which one step (output) can vary. So I'll do something like this (PHP):

abstract class MyAlgo
{
    function executeAlgo()   
    {
        $this->step1();
        $this->step2();
        $this->output();
    }

    function step1()
    {
       ...
    }

    function step2()
    {
        ...
    }

    abstract function output();
}

class Variation1 extends MyAlgo
{
    function output()
    {
        ...
    }
}

class Variation2 extends MyAlgo
{
    function output()
    {
        ...
    }
}

Upvotes: -1

Related Questions