Answers:
我更喜欢使用存储库模式来封装数据访问。简而言之,存储库负责加载特定对象所需的所有数据。像您的示例一样,假设您有一个Car对象。但是汽车的所有属性,品牌,型号,年份,所有者,功能(CD播放器,4WD等)都存储在整个数据库的各个表中。存储库确定如何加载和保存数据。如果需要多个较小的查询,可以,但是只有存储库模式需要知道这一点。调用存储库的服务层仅需要知道要调用哪个存储库。
然后可以将其与工作模式组合。因此,在您的示例中,服务层会说它需要加载汽车实体,它具有某种唯一标识符,然后将该标识符向下发送到存储库。存储库返回汽车实体。其他一些代码操纵汽车实体,然后将该实体发送回存储库,以便可以将其保存。
如果您真的想全力以赴,那么存储库层将只公开接口,例如ICarRepository。该存储库将包含一个工厂,服务层将使用该工厂来获取ICarRepository接口。所有数据库访问都将隐藏在界面的后面,这使单元测试变得更加容易。
我已经使用了策略模式来封装数据访问。通过此模式,您可以在通用界面后隐藏正在使用的存储类型。在界面中,在不考虑存储类型(文件,数据库,Web)的情况下定义数据访问方法。然后,对于当前的存储选择,在实现策略接口的类中,实现数据访问详细信息。这样,您的应用程序就不会在乎您使用的数据源。
您还可以构建一个服务层,该服务层使用当前的数据存储策略实例来定义更多特定于应用程序的细节,而不是将数据访问和业务逻辑混合在一起。
这是数据库工厂模式的示例;
using System.Reflection;
using System.Configuration;
public sealed class DatabaseFactory
{
public static DatabaseFactorySectionHandler sectionHandler = (DatabaseFactorySectionHandler)ConfigurationManager.GetSection("DatabaseFactoryConfiguration");
private DatabaseFactory() { }
public static Database CreateDatabase()
{
// Verify a DatabaseFactoryConfiguration line exists in the web.config.
if (sectionHandler.Name.Length == 0)
{
throw new Exception("Database name not defined in DatabaseFactoryConfiguration section of web.config.");
}
try
{
// Find the class
Type database = Type.GetType(sectionHandler.Name);
// Get it's constructor
ConstructorInfo constructor = database.GetConstructor(new Type[] { });
// Invoke it's constructor, which returns an instance.
Database createdObject = (Database)constructor.Invoke(null);
// Initialize the connection string property for the database.
createdObject.connectionString = sectionHandler.ConnectionString;
// Pass back the instance as a Database
return createdObject;
}
catch (Exception excep)
{
throw new Exception("Error instantiating database " + sectionHandler.Name + ". " + excep.Message);
}
}
}