C#和Visual Studio 2005中的程序集之间的循环引用

我正在努力标准化我的所有应用程序的分层/ n层设计的单一方式.

我试图让我的所有应用程序5分层.

码:

| UI |

         |

|业务对象|

         |

| OR-Mapper |

         |

|数据访问|

         |

| RDBMS |

假设我正在为用户开发具有登录/注销功能的应用程序.我在VS2005解决方案下创建了4个项目.每个项目都是上层4层中的一个.
我正在设计我的Business Object类,如下所示: –

public class User
{
    private string _username;
    public string Username
    {
        get { return _username; }
        set { _username = value; }
    }

    private string _password;
    public string Password
    {
        get { return _password; }
        set { _password = value; }
    }

    public User()
    {
    }

    public bool LogIn(String username, String password)
    {
        bool success = false;

        if (UserMapper.UsernameExists(username))
        {
            success = UserMapper.UsernamePasswordExists(username, password);
        }
        else
        {
            //do nothing
        }

        return success;
    }

    public bool LogOut()
    {
           bool success;
        //----some logic
           return success;
    }

    public static User GetUserByUsername(string username)
    {
        return UserMapper.GetUserByUsername(username);
    }

    public static UserCollection GetByUserTypeCode(string code)
    {
        return UserMapper.GetByUserTypeCode(code);
    }
}

这就是我给我的对象一些与现实场景相匹配的功能.这里GetByUsername()和GetByUserTypeCode()是getter函数.这些功能与现实世界的逻辑不匹配. Coz,在现实世界中,用户永远不会“通过用户名获取”或“通过UserTypeCode获取”.所以这些功能保持静止.

我的O-R Mapper层课程如下: –

public static class UserMapper
{
    public static bool UsernameExists(String username)
    {
        bool exists = false;

        if (UserDA.CountUsername(username) == 1)
        {
            exists = true;
        }

        return exists;
    }

    public static bool UsernamePasswordExists(String username, String password)
    {
        bool exists = false;

        if (UserDA.CountUsernameAndPassword(username, password) == 1)
        {
            exists = true;
        }

        return exists;
    }
}

最后,DA类如下: –

public static class UserDA
{
    public static int CountUsername(string username)
    {
        int count = -1;

        SqlConnection conn = DBConn.Connection;

        if (conn != null)
        {
            try
            {
                SqlCommand command = new SqlCommand();
                command.Connection = conn;
                command.CommandText = @"SELECT COUNT(*) 
                                FROM User 
                                WHERE User_name = @User_name";
                command.Parameters.AddWithValue("@User_name", username);

                command.Connection.Open();
                object idRaw = command.ExecuteScalar();
                command.Connection.Close();

                if (idRaw == DBNull.Value)
                {
                    count = 0;
                }
                else
                {
                    count = (int)idRaw;
                }
            }
            catch (Exception ex)
            {
                count = -1;
            }
        }

        return count;
    }  

    public static int CountUsernameAndPassword(string username, string password)
    {
        int count = 0;

        SqlConnection conn = DBConn.Connection;

        if (conn != null)
        {
            try
            {
                SqlCommand command = new SqlCommand();
                command.Connection = conn;
                command.CommandText = @"SELECT COUNT(*) 
                                FROM User 
                                WHERE User_name = @User_name AND Pass_word = @Pass_word";
                command.Parameters.AddWithValue("@User_name", username);
                command.Parameters.AddWithValue("@Pass_word", password);

                command.Connection.Open();
                object idRaw = command.ExecuteScalar();
                command.Connection.Close();

                if (idRaw == DBNull.Value)
                {
                    count = 0;
                }
                else
                {
                    count = (int)idRaw;
                }
            }
            catch (Exception ex)
            {
                count = 0;
            }
        }

        return count;
    }

    public static int InsertUser(params object[] objects)
    {
        int count = -1;

        SqlConnection conn = DBConn.Connection;

        if (conn != null)
        {
            try
            {
                SqlCommand command = new SqlCommand();
                command.Connection = conn;
                command.CommandText = @"INSERT INTO User(ID, User_name, Pass_word, RegDate, UserTypeCode, ActualCodeOrRoll) 
                                                            VALUES(@ID, @User_name, @Pass_word, @RegDate, @UserTypeCode, @ActualCodeOrRoll)";
                command.Parameters.AddWithValue("@ID", objects[0]);
                command.Parameters.AddWithValue("@User_name", objects[1]);
                command.Parameters.AddWithValue("@Pass_word", objects[2]);
                command.Parameters.AddWithValue("@RegDate", objects[3]);
                command.Parameters.AddWithValue("@UserTypeCode", objects[4]);
                command.Parameters.AddWithValue("@ActualCodeOrRoll", objects[5]);

                command.Connection.Open();
                count = command.ExecuteNonQuery();
                command.Connection.Close();
            }
            catch (Exception ex)
            {
                count = -1;
            }
        }

        return count;
    }

    public static SqlDataReader GetUserByUsername(string username)
    {
        SqlDataReader dataReader = null;

        SqlConnection conn = DBConn.Connection;

        if (conn != null)
        {
            try
            {
                SqlCommand command = new SqlCommand();
                command.Connection = conn;
                command.CommandText = @"SELECT * FROM User WHERE User_name = @User_name";
                command.Parameters.AddWithValue("@User_name", username);

                command.Connection.Open();

                dataReader = command.ExecuteReader(CommandBehavior.CloseConnection);

            }
            catch (Exception ex)
            {
                dataReader.Close();
                dataReader.Dispose();
            }
        }

        return dataReader;
    }

    public static SqlDataReader GetUserByUserTypeCode(string userTypeCode)
    {
        SqlDataReader dataReader = null;

        SqlConnection conn = DBConn.Connection;

        if (conn != null)
        {
            try
            {
                SqlCommand command = new SqlCommand();
                command.Connection = conn;
                command.CommandText = @"SELECT * FROM User WHERE UserTypeCode = @UserTypeCode";
                command.Parameters.AddWithValue("@UserTypeCode", userTypeCode);

                command.Connection.Open();

                dataReader = command.ExecuteReader(CommandBehavior.CloseConnection);

            }
            catch (Exception ex)
            {
                dataReader.Close();
                dataReader.Dispose();
            }
        }

        return dataReader;
    }
}

如果有人仔细检查这些类,他可以理解,O-R Mapper层需要BusinessObject-layer的引用. BusinessObject-层还需要O-R Mapper-layer的引用.

这应该创建循环依赖.

我该如何避免这个问题?

有人建议使用普通数据传输对象(DTO).但是,据我所知,根据OOP,现实世界对象的属性和功能应该组合在一起作为一个类.如果我使用DTO,那么如何将功能封装到类中?此外,我正在创建另一个没有任何属性(BO)的类.对我而言,这两种方式都违反了OOP.如果我这样做,那么这个世界的OOP是什么?相同的答案可以应用于“UserManager”类.

我找到了blog.

它讨论了实现接口.定义一个单独的接口,在BusinessObject中的数据类中实现它,并在BusinessObject和OR-Mapper层中针对您的接口进行编程.

但我不能这样做.

有人能用一个实际的例子告诉我吗?

最佳答案
我认为你可以做的一些事情可以帮助你的设计.我也认为您可能希望在Dependency Injection上阅读,因为它可能为您想要做的事情提供更好的设计模式.

假设你只想做你工作的东西:

>首先,从User类中删除静态方法,因为它们“创建”了用户,因此最好留在UserMapper上.
>之后,仍有许多方法可能使用User类的UserMapper功能.创建一个支持UserNameExists和UserNamePasswordExists方法的接口IUserLookup(或其他东西);将此接口放在与User类相同的项目中.
>在UserMapper类上实现IUserLookup,然后通过构造函数将其“注入”它使用静态方法创建的User类实例,所以基本上,当UserMapper创建User对象时,它为它们提供了对IUserLookup接口的引用.它实现了自己.

通过这种方式,用户只使用IUserLookup上的方法,这是在同一个解决方案中,因此不需要引用. UserMapper引用此解决方案,因此它可以创建User对象并实现IUserLookup接口.

转载注明原文:C#和Visual Studio 2005中的程序集之间的循环引用 - 代码日志