- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在努力标准化我所有应用程序的分层/n 层设计的一种单一方式。
我正在尝试将我所有的应用程序分为 5 层。
代码:
假设我正在开发一个具有用户登录/注销功能的应用程序。我正在 VS2005 解决方案下创建 4 个项目。每个项目都针对上 4 层之一。我正在按如下方式设计我的业务对象类:-
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 函数。这些功能与现实世界的逻辑不匹配。因为,在现实世界中,用户永远不会“通过用户名获取”或“通过 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 层的引用。 BusinessObject-层还需要引用O-R Mapper-层。
这应该会产生循环依赖。
如何避免这个问题?
有人建议使用纯数据传输对象 (DTO)。但是,据我所知,根据 OOP,真实世界对象的属性和功能应该作为一个类组合在一起。如果我使用 DTO 那么如何将功能封装到一个类中?此外,我正在创建另一个没有任何属性(BO)的类。对我来说,这在两个方面都违反了 OOP。如果我这样做,那么 OOP 在这个世界上有什么用?同样的答案也适用于“UserManager”类。
我找到了一个 blog .
它讨论了实现接口(interface)。定义一个单独的接口(interface),在 BusinessObject 的数据类中实现它,并针对 BusinessObject 和 OR-Mapper 层中的接口(interface)进行编程。
但我做不到。
任何人都可以通过实际示例向我展示吗?
最佳答案
我认为您可以一起做一些事情来帮助您进行设计。我还认为您可能想阅读 Dependency Injection可能会为您想要做的事情提供更好的设计模式。
假设您只想让现有的工作正常进行:
首先,从 User
类中删除 static
方法,因为它们“创建”用户,因此最好只留在 UserMapper
.
在那之后,仍然会有许多方法可能使用 User
类中的 UserMapper
功能。创建一个支持 UserNameExists
和 UserNamePasswordExists
方法的接口(interface) IUserLookup
(或其他东西);将此接口(interface)与 User
类放在同一个项目中。
在 UserMapper
类上实现 IUserLookup
,然后将其“注入(inject)”到它创建的 User
类实例中通过构造函数的静态方法,所以基本上,当 UserMapper
创建 User
对象时,它为它们提供了对它自己实现的 IUserLookup
接口(interface)的引用.
这样,User
只使用IUserLookup
上的方法,它们在同一个解决方案中,因此不需要引用。而 UserMapper
引用了这个解决方案,因此它可以创建 User
对象并实现 IUserLookup
接口(interface)。
关于c# - C# 和 Visual Studio 2005 程序集之间的循环引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/924382/
我想根据我使用的 visual studio 版本编译不同的东西,比如 #if VISUAL_STUDIO_VERSION > 2015 eventH?.Invoke(this, EventArgs.
在 Visual Studio 2010 中调试并将鼠标悬停在变量名称上时,我可以选择使用 3 种不同的内置可视化工具:文本、XML 和 HTML。 这是我所指的示例: 由于我越来越多地使用基于 JS
我将可视化编程语言理解为允许程序员在屏幕上操作图形(而不是文本)对象以构建功能的语言。 我在 C#、VB 等中看到的最接近的东西是 RAD 控件,但这只是组成 UI 和最简单的功能——甚至与语言本身无
我目前正在使用 Visual Studio 2015 来编程 ASP.NET Core 应用程序。我对安装 Visual Studio 2017 有以下疑问: 什么被认为是最佳实践和/或最干净的方法?
尝试从扩展和更新获取 Visual Studio 扩展时,出现以下错误:- 向 visualstudiogallery.msdn.microsoft.com/Services/VStudio/Exte
我已经开发了Windows服务,并且该服务正在我的帐户下在本地计算机上运行。当我尝试通过在Visual Studio 2008中将其作为一个过程附加该服务来调试该服务时,我得到“无法附加到该过程。 V
作为标准安装的一部分,Visual Studio Code 带有一个名为“Monokai Dimmed”的颜色主题。 有没有办法将它移植到 Visual Studio 2015?我检查了社区主题( h
Visual Studio Community Edition是否可以使用Visual Studio Online帐户上的存储库? 我一直为包含在Online帐户中的Visual Studio Onl
我正在使用文本可视化工具在 Visual Studio 中调试字符串变量。然而,似乎字符串中间的大部分不见了。这背后的原因是什么? 最佳答案 Visual Studio 中的 Text Visuali
我正在开始一个涉及使用多个 SDK 的新项目,包括: 英特尔凌动开发者 SDK 文本转语音 SDK(建议?) 某种网络摄像头和增强现实支持(建议?) 我目前有 2008,但我也可以安装 2010。是否
我想知道,如果我发送一个解决方案文件夹(它是用 visual studio C# 编写的),您可以在 visual studio for mac 中打开解决方案吗? 在visual studio 20
有没有办法在 Visual Studio Code 和 Visual Studio 中设置相同的快捷方式(而不必每次都手动更改它们)? 例如,我在 Visual Studio Code 中经常使用 A
我无法启用 实时可视化树 在 Visual Studio 2017 用于 UWP 应用程序 (C#)。这个工具在 VS2015 上工作,但在 VS2017 中从来没有为我工作过。它对我的 WPF 项目
我刚开始了解 Visual Studio Code。我想知道,我可以将 Visual Studio 替换为所有 .NET 开发相关的工作吗? 我可以节省 Visual Studio 许可的成本吗? V
我安装了具有有效许可证(Visual Studio 订阅)的 Visual Studio 2019 企业版(VS 2019 16.1.4),它运行良好。 突然之间,当我尝试打开项目或项目中的任何文件时
Visual Studio 2015 Pro 提供以下 错误 : error BC36716: Visual Basic 9.0 does not support implicit line cont
我正在我的 PC 中使用 .net Framework 2.0 和 Visual C#(Microsoft Visual Studio 2008)开发 Windows 应用程序。 完成我的项目后,我必
有什么方法可以在启动 VS 时禁用 VA X 并仅在需要时将其重新打开?因为它会导致一些滞后。我似乎在 VS 的选项或 VA 的选项中都找不到该选项。 最佳答案 持shift在 Visual Stud
我可以将 Visual Studio 命令提示符 与免费的 Visual C# Express 一起使用吗? Visual Studio 命令提示符 被引用 here : Run 'Visual St
这很容易成为 Visual Studio 历史上最烦人的“功能”之一,我不明白它为什么存在 -- 曾经 . 为什么 CodePlex 项目需要关心我使用的是什么版本的 Visual Studio? 在
我是一名优秀的程序员,十分优秀!