views:

424

answers:

3

I am new to design patterns and now I want to implement the Strategy patern. Here's my code:

namespace StrategyPattern
{
    public interface ISendBehavior
    {
        void Send();
    }

    public class SendAppointment : ISendBehavior
    {
        public void Send()
        {
            // send item
        }
    }

    public class SendTask : ISendBehavior
    {
        public void Send()
        {
            // send item
        }
    }

    public class SendItem
    {
        ISendBehavior _sendBehavior;

        public SendItem(ISendBehavior sendbehavior)
        {
            _sendBehavior = sendbehavior;
        }

        public void Send()
        {
            _sendBehavior.Send();
        }
    }

    /* CALL */

    public class Aanroep
    {
        public void Verzenden()
        {
            SendItem app = new SendItem(new SendAppointment());
            app.Send();
        }

    }
}

In the method Send in the class SendAppointment the item will be send. My question is, do I have to connect to the database in this class? If so, then I also have to connect to the database in SendTask. But at this point I am repeating myself right? So if a connection string changes, i have to modify this in every class. How can I solve this problem?

+1  A: 

How about initializing each implementor of ISendBehavior with yet another object that's responsible for the database connection?

Your Verzenden()-implementation would be something like

IDatabaseConnection connection = new DatabaseConnection();

SendItem app = new SendItem( new SendAppointment( connection ) );

and your ISendBehavior.Send() would be implemented like this

_databaseConnection.Send( ... ); // fill behavior-specific information here (perhaps with properties)

This way, you can reuse that IDatabaseConnection for any other classes.

Lennaert
Thnx for responding. I don't get really the last part. So the Send method in the interface now looks like this Send(IDatabaseConnection db)? And _databaseConnection is a member variable in ISendBehavior and in the method Send you do _databaseConnection = db? But how do I invoke the Send method? And where do I need to set the query's?
Martijn
You should notice that in the example code, I pass the DatabaseConnection to the SendAppointment-constructor (which will set the _databaseConnection member).In that DatabaseConnection, you store any database-related stuff. The quickest way would be to only store connection strings etc. in it and still perform the queries from the SendAppointment-class - This way, you only have to specify the connection strings once.(The cleanest way would be to put all database code in the extra class and let SendAppointment use (instances of) that class to perform database operations.)
Lennaert
So for the cleanest way I have to create another database class and let SendAppointment make an instance of it. This way, I don't have to send a connection as a parameter to SendAppointment() right? Because I create an instance in this method. This way the Send method of SendAppointment creates all the querys. Is this correct?
Martijn
I don't really see what you mean in your first sentence, but I think you're on the right track.However: think about the advantages and disadvantages of passing the connection to the SendAppointment-constructor as opposed to instantiating it inside the method.I tried to contrast the quickest and the cleanest way: The quickest way makes SendAppointment.Send create all the database queries by itself, while the cleaner way would extract database knowledge to the DatabaseConnection-class so SendAppointment doesn't have to know anything about the database. It's up to you to choose...
Lennaert
So, If I choose to go the cleaner way, I can use the Repository Pattern as suggested by Bruno Conde? Is that what you should do if you choose the cleanest way?
Martijn
Yes. The Repository pattern means that you create List-like classes that represent your database. These classes have methods like Add(), Find(). This means that your classes don't have to know anything about database, except that they can add/retrieve data from it. This makes your code much easier to read and write.
Lennaert
Thnx again. I'm sorry, I feel so stupid, but how can I implement this?
Martijn
Actually, that's quite easy (at least, as long as your domain model isn't too complex). Say you want to keep track of Appointments. Create a class AppointmentRepository. This will contain methods like Add( Appointment appointment), FindByID( int id ), etc. In these methods, you perform the SQL-queries and the construction of Appointments etc.. The same for Tasks etc.Note that if you implement a Repository-pattern, you won't have much need for the Strategy-pattern that you started with, since your "behaviors" will be implemented in the Repository classes.
Lennaert
+1  A: 

You could have another layer of abstraction for the database operations. This layer should be responsible for taking all the database requests centralizing the access. Connections strings should be configured externally, and the data mapping layer could access them directly.

The Repository Pattern is a good pattern for this layer that you can apply. It can sit between your domain objects and the data mapping layers.

bruno conde
Can give a pseudo code example?
Martijn
This article http://blogs.hibernatingrhinos.com/nhibernate/archive/2008/10/08/the-repository-pattern.aspx should help you. If your using Linq2SQL: http://geekswithblogs.net/AndrewSiemer/archive/2008/02/05/linq-to-sql---implementing-the-repository-pattern.aspx
bruno conde
I've read something about the Repository Pattern, but I don't see how I can apply this to my situation. Can you help me with that?
Martijn
+1 IMHO the database access should definitely be abstracted into a seperate assembly
AdamRalph
You mean I have to create in every method that implements the ISendBehavior has to create an instance of a database class?
Martijn
A: 

Since you don't like Lennaert answer of passing the connection to your class why not reverse it and create a connection class that uses a simple command pattern and pass your class to it as a the parameter?

Kelly