Code design:Advanced use of interfaces

by sunil ravulapalli /9. August 2010 17:37 /software-design /Comments (0)

Suppose, I have a class like this

public class EmployeeRepository
{
  public DataSet GetAll()
  {
    string connectionString = @"Data Source=.\SQLEXPRESS;AttachDbFilename=***.mdf;
    Integrated Security=True;User Instance=True";
    DataSet employee = new DataSet();
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
      string queryString = "SELECT EmpId, EmpName FROM Employee";
      SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);
      adapter.Fill(employee, "Employees");
      return employee;
    }
  }
}

Lets assume, I use it like this "several times" all over my implementaion code:

EmployeeRepository repository = new EmployeeRepository();
DataSet dataset = repository.GetAll();

Now, lets say we have a new class called UppercaseEmployeeRespository which looks like this. It is only slightly different from "EmployeeRepository".(notice i changed the query string):

public class UppercaseEmployeeRespository
{
  public DataSet GetAll()
  {
    string connectionString = @"Data Source=.\SQLEXPRESS;AttachDbFilename=***.mdf;
    Integrated Security=True;User Instance=True";
    DataSet employee = new DataSet();
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
      string queryString = "SELECT EmpId, UPPER(EmpName) FROM Employee";
      SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);

      adapter.Fill(employee, "Employees");
      return employee;
    }
  }
}

Now, I need to globally replace the use of "EmployeeRespository" with "UppercaseEmployeeRespository"? How do I do that? Simple, globally Find & Replace, "EmployeeRespository" with "UppercaseEmployeeRespository"? :) Well, in a badly designed solution, thats all you can do. But lets say we have chance to Re-Arch our solution, how can we restructure this code?Stage 1: Extract the interface and make the class implement the interface.

public interface IRepository
{
  DataSet GetAll();
}
public class EmployeeRepository : IRepository
{
  public DataSet GetAll()
  {
     string connectionString = @"Data Source=.\SQLEXPRESS;AttachDbFilename=***.mdf;
     Integrated Security=True;User Instance=True";
     DataSet employee = new DataSet();
     using (SqlConnection connection = new SqlConnection(connectionString))
     {
       string queryString = "SELECT EmpId, EmpName FROM Employee";
       SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);

       adapter.Fill(employee, "Employees");
       return employee;
     }
  }
}

Now, the implementaion code changes to

IRepository repository = new EmployeeRepository();
DataSet dataset = repository.GetAll();

Whoever gives you a new class, has to implement IRepository, the new class now looks like this:

public class UppercaseEmployeeRespository : IRepository
{
  public DataSet GetAll()
  {
    string connectionString = @"Data Source=.\SQLEXPRESS;AttachDbFilename=***.mdf;
    Integrated Security=True;User Instance=True";
    DataSet employee = new DataSet();
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
      string queryString = "SELECT EmpId, UPPER(EmpName) FROM Employee";
      SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);

      adapter.Fill(employee, "Employees");
      return employee;
    }
  }
}

Now, if you want to swap, you still have to globally Find & Replace "EmployeeRepository" with "UppercaseEmployeeRespository".

IRepository repository = new UppercaseEmployeeRespository();
DataSet dataset = repository.GetAll();

But, thats no good. What else can we do? Lets change our implementation code a little bit.Stage 2: Restructure the implementaion codeLets replace "new EmployeeRepository()" with a method call "RepositoryInstance.GetInstance()"where "GetInstance()" is a static method.

IRepository repository = new EmployeeRepository();
DataSet dataset = repository.GetAll();

becomes

IRepository repository = RepositoryInstance.GetInstance();
DataSet dataset = repository.GetAll();

where the class "RepositoryInstance" looks like this:

public static class RepositoryInstance
{
  public static IRepository GetInstance()
  {
    return new EmployeeRepository();
  }
}

The static function GetInstance() currently returns an instance of EmployeeRepository. This looks great! Now, if I want to swap out all "EmployeeRepository" with "UppercaseEmployeeRespository" all I have to replace is one line of code in "GetInstance()". Replace "return new EmployeeRepository()" with "return new UppercaseEmployeeRespository()"; Thats it!!Final, code recap:

public interface IRepository
{
  DataSet GetAll();
}

public class EmployeeRepository : IRepository
{
  public DataSet GetAll()
  {
    string connectionString = @"Data Source=.\SQLEXPRESS;AttachDbFilename=***.mdf;
    Integrated Security=True;User Instance=True";
    DataSet employee = new DataSet();
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
      string queryString = "SELECT EmpId, EmpName FROM Employee";
      SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);
      adapter.Fill(employee, "Employees");
      return employee;
    }
  }
}


public class UppercaseEmployeeRespository : IRepository
{
  public DataSet GetAll()
  {
    string connectionString = @"Data Source=.\SQLEXPRESS;AttachDbFilename=***.mdf;
    Integrated Security=True;User Instance=True";
    DataSet employee = new DataSet();
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
      string queryString = "SELECT EmpId, UPPER(EmpName) FROM Employee";
      SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);

      adapter.Fill(employee, "Employees");
      return employee;
    }
  }
}

IRepository repository = RepositoryInstance.GetInstance();
DataSet dataset = repository.GetAll();

public static class RepositoryInstance
{
  public static IRepository GetInstance()
  {
    return new UppercaseEmployeeRespository();
  }
}

blog comments powered by Disqus