Reputation: 12507
I'm working on a simple, internal ASP.NET app for a small company. I've designed the data access layer so it's database-agnostic.
I have the following:
And finally, I have a static class that creates an IDataHelper for the data access classes to call. In the future it will create the appropriate helper based on the database specified in the config file. For now it's just hard-coded to create a MySqlHelper:
public static class DataHelperContainer
{
private static IDataHelper dataHelper;
public static IDataHelper DataHelper
{
get { return dataHelper; }
}
static DataHelperContainer()
{
string connectionString = ConfigurationManager
.ConnectionStrings["myapp"].ConnectionString;
// Support for other databases will be added later.
dataHelper = new MySqlHelper(connectionString);
}
}
My questions are:
Sorry about the long post and multiple questions. :)
Thanks!
Upvotes: 1
Views: 425
Reputation: 8991
You could name it DataHelperFactory.
It's a good pattern. You definitely don't want to leak things like ConfigurationManager.ConnectionStrings["myapp"].ConnectionString
all over the place! A fault is that it's static which makes it difficult to test any code using it.
This is most like the factory pattern or possibly service locator (not strategy).
Currently, your code will look like this:
public class MyClass
{
public void DoSomething()
{
var helper = DataHelperFactory.Create();
helper.ExecuteNonQuery("some sql");
}
}
This is not easily testable because you'd have to modify your app.config in order to change what helper you get back in your test. Maybe you want to test what happens when helper.ExecuteNotQuery throws an exception.
Using dependency injection, your class would change to:
public class MyClass
{
private IDataHelper helper;
public MyClass(IDataHelper helper)
{
this.helper = helper;
}
public void DoSomething()
{
helper.ExecuteNonQuery("some sql");
}
}
The trade-off here is that now you have to deal with supplying the IDataHelper dependency in the calling context. This is where IoC containers like Unity, Windsor, and StructureMap enter. This is more complex though and maybe not worth it in your situation.
Using a factory (even static) is great. It allows you to use other patterns like the decorator to add additional behavior. Consider a scenario where you want to sanitize your sql string and make sure nothing bad is sent to your db:
public class SanitizingDataHelper : IDataHelper
{
private IDataHelper helper;
public SanitizingDataHelper(IDataHelper helper)
{
this.helper = helper;
}
public void ExecuteNotQuery(string sql)
{
sql = EscapeHarmfulSql(sql);
helper.ExecuteNonQuery(sql);
}
private string EscapeHarmfulSql(string sql)
{
...
}
}
Your factory can then do something like this:
public class DataHelperFactory
{
public IDataHelper Create()
{
...
var helper = new MySqlDataHelper(connectionString);
return new SanitizingDataHelper(helper);
}
}
Upvotes: 2
Reputation: 4015
For the data access classes it seems like it might be a Data Access Objects (DAO) pattern, but I'm not sure exactly how you are implementing that. Andy West is right you definitely have a Strategy pattern in there.
Upvotes: 1
Reputation: 14234
It looks like the Strategy pattern. With the strategy pattern would would be able to change the underlying functionality during the runtime of the program, and would be able to create new functionality without changing the basic flow of your data layer. [Functions are guarantied via the IHelper interface]
Upvotes: 4