1. 就不能不换DB吗?

A: 你既然有两个版本,两倍的工作量也是必然的。
A: 菜鸟程序员碰到问题,只会用时间来摆平。

2. 最基本的数据访问程序

class Program
{
    static void Main(string[] args)
    {
        User user = new User();

        SqlserverUser su = new SqlserverUser();
        su.Insert(user);
        su.GetUser(1);

        Console.Read();
    }
}

class User
{
    private int _id;
    public int ID
    {
        get { return _id; }
        set { _id = value; }
    }

    private string _name;
    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }
}

class SqlserverUser
{
    public void Insert(User user)
    {
        Console.WriteLine("在Sqlserver中给User表增加一条记录");
    }

    public User GetUser(int id)
    {
        Console.WriteLine("在Sqlserver中根据ID得到User表一条记录");
        return null;
    }
}

A: SqlserverUser su = new SqlserverUser();使得su这个对象被框在SQL Server上,如果这里能够灵活点,也就是多态,就没有那么麻烦。
A: 工厂方法模式是定义一个用于创建对象的接口,让子类决定实例化哪个类。

3. 用了工厂方法模式的数据访问程序

代码结构图:
图1

class Program
{
    static void Main(string[] args)
    {
        User user = new User();
        //AbstractFactory factory = new SqlServerFactory();
        IFactory factory = new AccessFactory();

        IUser iu = factory.CreateUser();

        iu.Insert(user);
        iu.GetUser(1);

        Console.Read();
    }
}

class User
{
    private int _id;
    public int ID
    {
        get { return _id; }
        set { _id = value; }
    }

    private string _name;
    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }
}

interface IUser
{
    void Insert(User user);

    User GetUser(int id);
}

class SqlserverUser : IUser
{
    public void Insert(User user)
    {
        Console.WriteLine("在Sqlserver中给User表增加一条记录");
    }

    public User GetUser(int id)
    {
        Console.WriteLine("在Sqlserver中根据ID得到User表一条记录");
        return null;
    }
}

class AccessUser : IUser
{
    public void Insert(User user)
    {
        Console.WriteLine("在Access中给User表增加一条记录");
    }

    public User GetUser(int id)
    {
        Console.WriteLine("在Access中根据ID得到User表一条记录");
        return null;
    }
}

interface IFactory
{
    IUser CreateUser();
}

class SqlServerFactory : IFactory
{
    public IUser CreateUser()
    {
        return new SqlserverUser();
    }
}

class AccessFactory : IFactory
{
    public IUser CreateUser()
    {
        return new AccessUser();
    }
}

A: IFactory factory = new AccessFactory();由于多态,对象iu事先根本不知道是在访问哪个数据库,却可以在运行时很好的完成工作,这就是所谓的业务逻辑与数据访问的解耦。
A: 如果增加表呢?
B: 要增加好多类。
A: 多写类有什么关系,只要能增加灵活性,以后就不用加班了。

4. 使用了抽象工程模式的数据访问程序

代码结构图:
图2

class Program
{
    static void Main(string[] args)
    {
        User user = new User();
        Department dept = new Department();

        //AbstractFactory factory = new SqlServerFactory();
        IFactory factory = new AccessFactory();
        IUser iu = factory.CreateUser();

        iu.Insert(user);
        iu.GetUser(1);

        IDepartment id = factory.CreateDepartment();
        id.Insert(dept);
        id.GetDepartment(1);

        Console.Read();
    }
}

class User
{
    private int _id;
    public int ID
    {
        get { return _id; }
        set { _id = value; }
    }

    private string _name;
    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }
}

class Department
{
    private int _id;
    public int ID
    {
        get { return _id; }
        set { _id = value; }
    }

    private string _deptName;
    public string DeptName
    {
        get { return _deptName; }
        set { _deptName = value; }
    }
}

interface IUser
{
    void Insert(User user);

    User GetUser(int id);
}

class SqlserverUser : IUser
{
    public void Insert(User user)
    {
        Console.WriteLine("在Sqlserver中给User表增加一条记录");
    }

    public User GetUser(int id)
    {
        Console.WriteLine("在Sqlserver中根据ID得到User表一条记录");
        return null;
    }
}

class AccessUser : IUser
{
    public void Insert(User user)
    {
        Console.WriteLine("在Access中给User表增加一条记录");
    }

    public User GetUser(int id)
    {
        Console.WriteLine("在Access中根据ID得到User表一条记录");
        return null;
    }
}

//用于客户端访问,解除与具体数据库访问的耦合
interface IDepartment
{
    void Insert(Department department);

    Department GetDepartment(int id);
}

class SqlserverDepartment : IDepartment
{
    public void Insert(Department department)
    {
        Console.WriteLine("在Sqlserver中给Department表增加一条记录");
    }

    public Department GetDepartment(int id)
    {
        Console.WriteLine("在Sqlserver中根据ID得到Department表一条记录");
        return null;
    }
}

class AccessDepartment : IDepartment
{
    public void Insert(Department department)
    {
        Console.WriteLine("在Access中给Department表增加一条记录");
    }

    public Department GetDepartment(int id)
    {
        Console.WriteLine("在Access中根据ID得到Department表一条记录");
        return null;
    }
}

interface IFactory
{
    IUser CreateUser();

    IDepartment CreateDepartment();
}

class SqlServerFactory : IFactory
{
    public IUser CreateUser()
    {
        return new SqlserverUser();
    }

    public IDepartment CreateDepartment()
    {
        return new SqlserverDepartment();
    }
}

class AccessFactory : IFactory
{
    public IUser CreateUser()
    {
        return new AccessUser();
    }

    public IDepartment CreateDepartment()
    {
        return new AccessDepartment();
    }
}

A: 现在显然在你的数据库中有很多的表,而SQL Server与Access又是不同的分类,所有解决这种涉及到多个产品系列的问题,有一个专门的工厂模式叫抽象工厂模式。

5. 抽象工厂模式

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

图3
A: AbstractProductA和A不是tractProductB是两个抽象产品,之所以抽象,是因为它们都有可能有不同的实现。
B: IFactory是一个抽象的工厂接口,它里面应该包含所有的产品创建的抽象方法。
A: 通常是在运行时刻在创建一个ConcreteFactory类的实例,这个具体的工厂再创建特定的产品对象,也就是说,为创建不同的产品对象,客户端应使用不同的具体工厂。

6. 抽象工厂模式的优点与缺点

A:好处便是易于交换产品系列,由于具体工厂类,在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置。设计不能防止需求更改,理想是让改动变的最小。
A: 它让具体的创建实例过程与客户端分离,客户端是通过它们的抽象接口操纵实例,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。
A: 比如我们现在要增加表Project,你需要改动那些地方?
B: 啊,那就至少要增加3个类,还要该3个工厂,这太糟糕了。
A: 客户端代码显然不会只有一个,如果我有100个调用数据库访问的类,是不是就要更改100次IFactory factory = new AccessFactory();才行?

7. 用简单工厂来改进抽象工厂

去除实例化工厂,其而代之的是一个DataAccess类,用一个简单工厂模式实现。
图4

class Program
{
    static void Main(string[] args)
    {
        User user = new User();
        Department dept = new Department();

        IUser iu = DataAccess.CreateUser();

        iu.Insert(user);
        iu.GetUser(1);

        IDepartment id = DataAccess.CreateDepartment();
        id.Insert(dept);
        id.GetDepartment(1);

        Console.Read();
    }
}

class User
{
    private int _id;
    public int ID
    {
        get { return _id; }
        set { _id = value; }
    }

    private string _name;
    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }
}

class Department
{
    private int _id;
    public int ID
    {
        get { return _id; }
        set { _id = value; }
    }

    private string _deptName;
    public string DeptName
    {
        get { return _deptName; }
        set { _deptName = value; }
    }
}

interface IUser
{
    void Insert(User user);

    User GetUser(int id);
}

class SqlserverUser : IUser
{
    public void Insert(User user)
    {
        Console.WriteLine("在Sqlserver中给User表增加一条记录");
    }

    public User GetUser(int id)
    {
        Console.WriteLine("在Sqlserver中根据ID得到User表一条记录");
        return null;
    }
}

class AccessUser : IUser
{
    public void Insert(User user)
    {
        Console.WriteLine("在Access中给User表增加一条记录");
    }

    public User GetUser(int id)
    {
        Console.WriteLine("在Access中根据ID得到User表一条记录");
        return null;
    }
}

interface IDepartment
{
    void Insert(Department department);

    Department GetDepartment(int id);
}

class SqlserverDepartment : IDepartment
{
    public void Insert(Department department)
    {
        Console.WriteLine("在Sqlserver中给Department表增加一条记录");
    }

    public Department GetDepartment(int id)
    {
        Console.WriteLine("在Sqlserver中根据ID得到Department表一条记录");
        return null;
    }
}

class AccessDepartment : IDepartment
{
    public void Insert(Department department)
    {
        Console.WriteLine("在Access中给Department表增加一条记录");
    }

    public Department GetDepartment(int id)
    {
        Console.WriteLine("在Access中根据ID得到Department表一条记录");
        return null;
    }
}

class DataAccess
{
    private static readonly string db = "Sqlserver";
    //private static readonly string db = "Access";

    public static IUser CreateUser()
    {
        IUser result = null;
        switch (db)
        {
            case "Sqlserver":
                result = new SqlserverUser();
                break;
            case "Access":
                result = new AccessUser();
                break;
        }
        return result;
    }

    public static IDepartment CreateDepartment()
    {
        IDepartment result = null;
        switch (db)
        {
            case "Sqlserver":
                result = new SqlserverDepartment();
                break;
            case "Access":
                result = new AccessDepartment();
                break;
        }
        return result;
    }
}

B: 客服端没有出现一个SQL Server或Access的字样,达到了解耦的目的。但是增加一个时,需要增长case。

8. 用反射+抽象工厂的数据访问程序

A: 考虑可不可以在程序里不写'如果是SqlServer就去实例化SQL Server数据库相关类'这样的语句,而是根据字符串db额值去某个地方找要实例化的类是哪一个
B: 因为这里是字符串,可以用变量有处理,也就是根据需要更换。
图5

class Program
{
    static void Main(string[] args)
    {
        User user = new User();
        Department dept = new Department();

        IUser iu = DataAccess.CreateUser();

        iu.Insert(user);
        iu.GetUser(1);

        IDepartment id = DataAccess.CreateDepartment();
        id.Insert(dept);
        id.GetDepartment(1);

        Console.Read();
    }
}

class User
{
    private int _id;
    public int ID
    {
        get { return _id; }
        set { _id = value; }
    }

    private string _name;
    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }
}

class Department
{
    private int _id;
    public int ID
    {
        get { return _id; }
        set { _id = value; }
    }

    private string _deptName;
    public string DeptName
    {
        get { return _deptName; }
        set { _deptName = value; }
    }
}

interface IUser
{
    void Insert(User user);

    User GetUser(int id);
}

class SqlserverUser : IUser
{
    public void Insert(User user)
    {
        Console.WriteLine("在Sqlserver中给User表增加一条记录");
    }

    public User GetUser(int id)
    {
        Console.WriteLine("在Sqlserver中根据ID得到User表一条记录");
        return null;
    }
}

class AccessUser : IUser
{
    public void Insert(User user)
    {
        Console.WriteLine("在Access中给User表增加一条记录");
    }

    public User GetUser(int id)
    {
        Console.WriteLine("在Access中根据ID得到User表一条记录");
        return null;
    }
}

interface IDepartment
{
    void Insert(Department department);

    Department GetDepartment(int id);
}

class SqlserverDepartment : IDepartment
{
    public void Insert(Department department)
    {
        Console.WriteLine("在Sqlserver中给Department表增加一条记录");
    }

    public Department GetDepartment(int id)
    {
        Console.WriteLine("在Sqlserver中根据ID得到Department表一条记录");
        return null;
    }
}

class AccessDepartment : IDepartment
{
    public void Insert(Department department)
    {
        Console.WriteLine("在Access中给Department表增加一条记录");
    }

    public Department GetDepartment(int id)
    {
        Console.WriteLine("在Access中根据ID得到Department表一条记录");
        return null;
    }
}

class DataAccess
{
    private static readonly string AssemblyName = "抽象工厂模式";
    private static readonly string db = ConfigurationManager.AppSettings["DB"];
    
    public static IUser CreateUser()
    {
        string className = AssemblyName + "." + db + "User";
        return (IUser)Assembly.Load(AssemblyName).CreateInstance(className);
    }

    public static IDepartment CreateDepartment()
    {
        string className = AssemblyName + "." + db + "Department";
        return (IDepartment)Assembly.Load(AssemblyName).CreateInstance(className);
    }
}

9. 用反射+配置文件实现数据库访问程序

A: 在用简单工厂的地方,都可以考虑用反射技术来去除switch或if,解除分支判断的耦合。


yuanoung
10 声望1 粉丝

« 上一篇
观察者模式
下一篇 »
状态模式

引用和评论

0 条评论