怎样才能容易更换DB

//怎样才能容易更换DB
//写一个可以对用户插入和获取的方法
namespace switchDB
{
    class User
    {
        public int ID { get; set; }
        public string Name { get; set; }
    }
    class SqlServerUser
    {
        public void Insert(User user)
        { }
        public void GetUser(int id)
        { }
    }
    class Program
    {
        static void Main(string[] args)
        {
            User u = new User();
            SqlServerUser ssu = new SqlServerUser();
            ssu.Insert(u);
            ssu.GetUser(1);
        }
    }
}
这里的问题是SqlServerUser被硬编码了,只能使用SqlServer,要是多态的话就好了,使用抽象工厂修改:

namespace switchDB
{
    class User
    {
        public int ID { get; set; }
        public string Name { get; set; }
    }
    interface IUser
    {
        void Insert(User user);
        void GetUser(int id);
    }

    class SqlServerUser : IUser
    {
        public void Insert(User user)
        { }
        public void GetUser(int id)
        { }
    }
    class AccessUser : IUser
    {
        public void Insert(User user)
        { }
        public void GetUser(int id)
        { }
    }
    //定义IFactory接口
    interface IFactory
    {
        IUser CreateUser();
    }
    //抽象工厂
    class SqlServerFactory : IFactory
    {
        public IUser CreateUser()
        {
            return new SqlServerUser();
        }
    }
    class AccessFactory : IFactory
    {
        public IUser CreateUser()
        {
            return new AccessUser();
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            User u = new User();
            SqlServerFactory f = new SqlServerFactory();
            IUser it = f.CreateUser();
            it.Insert(u);
            it.GetUser(1);
        }
    }
}

这样以后增加表Department,就需要增加IDepartment,并实现SqlServerDepartment,和AccessDepartment,还要修改IFactory增加CreateDepartment接口方法,并且在SqlServerFactory和AccessFactory分别实现。其中增加三个是必须的,但是修改IFactory,SqlServerFactory和AccessFactory是多点多于的,也是不可容忍的。
使用简单工厂改进:
namespace switchDB
{
    class User
    {
        public int ID { get; set; }
        public string Name { get; set; }
    }
    interface IUser
    {
        void Insert(User user);
        void GetUser(int id);
    }

    class SqlServerUser : IUser
    {
        public void Insert(User user)
        { }
        public void GetUser(int id)
        { }
    }
    class AccessUser : IUser
    {
        public void Insert(User user)
        { }
        public void GetUser(int id)
        { }
    }
    class DateAccess
    {
        private static readonly string db = "sqlserver";
        public static IUser CreateUser()
        {
            IUser result = null;
            switch(db)
            {
                case "sqlserver":
                    result = new SqlServerUser();
                    break;
                case "access":
                    result = new AccessUser();
                    break;
            }
            return result;
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            User u = new User();
            IUser iu = DateAccess.CreateUser();
            iu.Insert(u);
            iu.GetUser(1);
        }
    }
}


使用简单工厂放弃IFactory,SqlServerFactory,AccessFactory这三个类,用DataAccess来改进,将来要是要用Oracle,就在DataAccess中增加一个Case,使用这个分支也是不完美的,要是我们可以根据字符串db的值,去某一个地方去找应该实例化的类,这样我们就可以不使用swith了,这种编程方式叫做  依懒注入,使用net反射就可以了:
格式:Assembly.Load("程序集名称").CreateInstance("类的全权名");
只要引入Using System.Reflection;就可以了。
使用反射和不使用发射比较:
//常规
IUser result = new SqlServerUser();
//反射
using System.Reflection;

反射中,可以灵活替换"程序集名称"和"类的全权名",灵活性和可以替换性达到了。
例如:
    class DateAccess
    {
        private static readonly string AssemblyName = "factory";
        private static readonly string db = "sqlserver";
        public static IUser CreateUser()
        {
            string className = AssemblyName + "." + db + "user";
            return (IUser)Assembly.Load(AssemblyName).CreateInstance(className);
        }
    }

修改之后我们就和switch说再见了,但是我们每次修改数据库,还是修改了db这个字符串的值,要不修改它就更好了,符合开发-封闭原则
使用反射+配置文件再作改进:
利用配置文件来解决更改DataAccess的问题
添加一个App.Config文件:
<Configuration>
<appSettings>
<add key="db" value="sqlserver">
</appSettings>
</Configuration>

代码:
using System.Configuration;
private static readonly string db = ConfigurationManager.AppSettings["db"];
现在我们应用反射,抽象工厂解决了数据库访问,可维护可扩展问题。
从这个角度,所有的用简单工厂的地方,都可以考虑修改为反射去除switch来完成。



下面试调用静态方法的反射运用:

public class T_SizeType
{
   public static bool pro_T_SizeType_SelectAll(string p_ConnString)
   {
       return true;
   }
}


class Program
{
   static void Main(string[] args)
   {
       object[] arg = new object[1]{string.Empty};
       typeof(T_SizeType).InvokeMember("pro_T_SizeType_SelectAll",
          BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, arg);
   }
}

posted @ 2013-02-25 11:47  八神吻你  阅读(353)  评论(1编辑  收藏  举报