On a boring Saturday evening, I was having a conversation with my Java friends whom I hadn't seen for a while. He kept on telling me how good the Java and J2EE world is, that I should get into the Java world and very soon will fall in love with it. I of course defend it vigorously with the greatness of C# and .NET, and he is the one who should switch to C# and .NET, not the other way around. Finally, we both decided to implement the DAO(Data Access Object) pattern in both languages just for the fun of it.
Before diving into the code, what is Data Access Object? DAO manages the connection with the data source to obtain and store data. It provides an abstract and encapsulated layer to the data source.
The sample code provided below is just a skeleton demonstrating the DAO pattern. There is no logic at all to actually talk to any data storage mechanism.
DAO.csusing System;using DataFactory;using DAOInterface;using Model;
namespace DAO{ public class Client { public static void Main(string[] args) { DAOFactory Factory = SqlServerDAOFactory.getDAOFactory(DAOFactory.SQLSERVER); IDAO custDAO = Factory.getCustomerDAO(); if(custDAO.insert()) Console.WriteLine("Success");
Factory = OracleDAOFactory.getDAOFactory(DAOFactory.ORACLE); custDAO = Factory.getCustomerDAO(); if(custDAO.insert()) Console.WriteLine("Success"); } }}
DAOFactory.csusing System;
using DAOInterface;using SQLServer;using Oracle;
namespace DataFactory{ public abstract class DAOFactory { public const int SQLSERVER = 1; public const int ORACLE = 2;
public abstract IDAO getCustomerDAO(); public abstract IDAO getOrderDAO();
public static DAOFactory getDAOFactory(int whichFactory) { switch (whichFactory) { case SQLSERVER: return new SqlServerDAOFactory(); case ORACLE: return new OracleDAOFactory(); default: return null; } } }
public class SqlServerDAOFactory : DAOFactory { public override IDAO getCustomerDAO() { return new SqlServerCustomerDAO(); }
public override IDAO getOrderDAO() { return new SqlServerOrderDAO(); } }
public class OracleDAOFactory : DAOFactory { public override IDAO getCustomerDAO() { return new OracleCustomerDAO(); }
public override IDAO getOrderDAO() { return new OracleOrderDAO(); } }}
DAOInterface.csusing Model;
namespace DAOInterface{ public interface IDAO { bool insert(); bool delete(); Customer find(int Id); bool update(); } }
Model.csusing System;
namespace Model{ [Serializable] public class Customer { private int _customernumber; public int CustomerNumber { get { return _customernumber; } set { _customernumber = value; } }
private string _name; public string Name { get { return _name; } set { _name = value; } } } }
SQLServer.csusing System;using DAOInterface;using Model;
namespace SQLServer{ public abstract class SqlServerLayer { public bool Connect() { Console.WriteLine("Code to connect to SQL SERVER"); return true; } } public class SqlServerCustomerDAO : SqlServerLayer, IDAO { public SqlServerCustomerDAO() {}
public bool insert() { if (Connect()) { Console.WriteLine("Code to insert a customer record into SQL SERVER database"); return true; } return false; }
public bool delete() { return true; }
public Customer find(int CustNo) { return new Customer(); }
public bool update() { return true; } }
public class SqlServerOrderDAO : SqlServerLayer, IDAO { public SqlServerOrderDAO() {}
public bool insert() { if(Connect()) return true; return false; }
public Customer find(int OrderNo) { return new Customer(); }
public bool update() { return true; } } }
Oracle.csusing System;using DAOInterface;using Model;
namespace Oracle{ public abstract class OracleLayer { public bool Connect() { Console.WriteLine("Code to connect to ORACLE"); return true; } } public class OracleCustomerDAO : OracleLayer, IDAO { public OracleCustomerDAO() {}
public bool insert() { if (Connect()) { Console.WriteLine("Code to insert customer record into ORACLE database"); return true; } return false; }
public class OracleOrderDAO : OracleLayer, IDAO { public OracleOrderDAO() {}
public bool update() { return true; } }}
Run the build.bat batch file to compile everything. You can again use VS .NET 200* if you prefer.
Build.batcsc /t:library Model.cscsc /r:Model.dll /t:library DAOInterface.cscsc /r:DAOInterface.dll /r:Model.dll /t:library SQLServer.cscsc /r:DAOInterface.dll /r:Model.dll /t:library Oracle.cscsc /r:DAOInterface.dll /r:SQLServer.dll /r:Oracle.dll /t:library DAOFactory.cscsc /r:DAOFactory.dll /r:DAOInterface.dll /r:Model.dll DAO.cs
I intentionally divide it into many DLLs to seperate its functionalities and also for easy reading. You can of course mix it anyway you like. If you read the code carefully, you will notice that the factory pattern is in used here.
Even though the two implementations looks very much alike, I believe the C# code is much cleaner and finer.
Hope it helps
The melody of logic will always play out the truth. ~ Narumi Ayumu, Spiral
icelava wrote:This was something that I actually wanted to write about.
Oh yea, junp in and see if anything you can improve to make the code cleaner and better. The more I'm experimenting with different patterns, the more I discover that there are so many better ways or not so good ways to spit out code. btw, I reviewed my own code and changed the DAO to use the strategy pattern to replace the Factory pattern. Below is the new change:
DAO.csusing System;// using DataFactory; // Factory patternusing DataStrategy; // Strategy pattern hereusing DAOInterface;using Model;
namespace DAO{ public class Client { public static void Main(string[] args) { Context DataContext = new Context(new SqlServerDAOStrategy()); IDAO custDAO = DataContext.Strategy.getCustomerDAO(); if(custDAO.insert()) Console.WriteLine("Success"); DataContext.Strategy = new OracleDAOStrategy(); custDAO = DataContext.Strategy.getCustomerDAO(); if(custDAO.insert()) Console.WriteLine("Success"); } }}
DAOStrategy.csusing System;using DAOInterface;using SQLServer;using Oracle;
namespace DataStrategy{ public abstract class DAOStrategy { public abstract IDAO getCustomerDAO(); public abstract IDAO getOrderDAO(); } public class SqlServerDAOStrategy : DAOStrategy { public override IDAO getCustomerDAO() { return new SqlServerCustomerDAO(); }
public class OracleDAOStrategy : DAOStrategy { public override IDAO getCustomerDAO() { return new OracleCustomerDAO(); }
public override IDAO getOrderDAO() { return new OracleOrderDAO(); } } public class Context { private DAOStrategy _strategy; public DAOStrategy Strategy { get { return _strategy; } set { _strategy = value; } // didn't check for null object here } public Context(DAOStrategy Strategy) { this._strategy = Strategy; } }}
Important point: The context class allows us to remove the switch clause found in the factory pattern which makes it looks more cleaner. However, with the Strategy pattern, client has to directly instantiate the SQL Server and Oracle DAO which is not found in the Factory pattern.
Replace these 2 lines csc /r:DAOInterface.dll /r:SQLServer.dll /r:Oracle.dll /t:library DAOFactory.cscsc /r:DAOFactory.dll /r:DAOInterface.dll /r:Model.dll DAO.cswith these 2 lines below for compilationcsc /r:DAOInterface.dll /r:SQLServer.dll /r:Oracle.dll /t:library DAOStrategy.cscsc /r:DAOStrategy.dll /r:DAOInterface.dll /r:Model.dll DAO.cs