在一个简单的多层体系结构中,我必须在哪个层实现类似于解析文件的内容。例如:我有一个文件,我必须将特定信息提取到一个对象中。我认为这是数据访问,因为业务层需要数据。这些数据的来源和来源并不是重点。你同意吗?
发布于 2015-10-09 07:22:31
我建议停止用“层”来思考,开始用“模块”来思考。现在,您的数据访问层只包含数据库访问模块。所以就在它旁边,你会把文件访问模块。该模块与数据库访问模块在哪些模块可以引用,哪些模块可以引用方面与数据库访问模块处于同一层。但是它可能是单独的库,就像数据库访问模块是它自己的库一样(我强烈希望如此)。
更好的情况是,如果您有一个保存和加载业务数据的抽象。然后,数据访问层(及其包含模块)将包含此抽象的实现。因此,您将拥有SaveDataInDatabase、SaveDataInFileX和SaveDataInFileY类。然后,业务代码将在不知道或不关心数据将如何持久化的情况下使用此抽象。
发布于 2015-10-09 14:22:02
从你在基本层面上的描述来看,你是:
存储库模式解决了这个问题。它涉及三种主要类型的课程:
这种模式的关键是为每种类型的类实现接口。让我们来看看如何以这种方式对博客进行建模和持久化。
让我们从域模型开始:
public class Blog
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}别太花哨了。接下来,我们需要定义我们的接口,首先通过定义博客存储库的接口。
public interface IBlogRepository
{
Blog Find(int id);
void Create(Blog blog);
void Update(Blog blog);
void Delete(Blog blog);
}IBlogRepository接口主要集中在域模型上,而没有提到持久性是如何实际实现的。这为应用程序的其余部分提供了一层解耦。
接下来,blog网关接口允许存储库在数据存储上预先形成特定的CRUD操作(创建、读取、更新、删除)。
public interface IBlogGateway
{
IList<IDictionary<string, object>> Load();
void Create(int id, string name, string description);
void Update(int id, string name, string description);
void Delete(int id);
}最好让“网关”不了解您的领域模型,因为这将提供最大的灵活性,以有限的影响“网关”改变您的领域模型,并以有限的影响您的领域模型。
Load方法只返回字典对象的列表,这是一种很好的通用数据格式。
最后一个接口是博客工厂对象,它负责创建域模型的实例并将通用数据映射到Blog对象。
public interface IBlogFactory
{
Blog CreateInstance(IDictionary<string, object> data);
void UpdateInstance(IDictionary<string, object> data, Blog instance);
}现在我们已经定义了接口,让我们从创建一个实现BlogRepository接口的IBlogRepository类开始:
public class BlogRepository : IBlogRepository
{
private IBlogGateway gateway;
private IBlogFactory factory;
private IList<Blog> cache;
private IList<Blog> Cache
{
get
{
if (cache == null)
{
var data = gateway.Load();
cache = new List<Blog>();
foreach (var record in data)
{
cache.Add(factory.CreateInstance(record));
}
}
return cache;
}
}
public BlogRepository(IBlogGateway gateway = null, IBlogFactory factory = null)
{
this.gateway = gateway ?? new BlogFileGateway(@"C:\Path\To\Blogs.txt");
this.factory = factory ?? new BlogFactory();
}
public Blog Find(int id)
{
Cache.SingleOrDefault(b => b.Id == id);
}
public void Create(Blog blog)
{
Cache.Add(blog);
gateway.Create(blog.Id, blog.Name, blog.Description);
}
public void Update(Blog blog)
{
gateway.Update(blog.Id, blog.Name, blog.Description);
}
public void Delete(Blog blog)
{
Cache.RemoveAll(b => b.Id == blog.Id);
gateway.Delete(blog.Id);
}
}现在我们可以开始看看每一块是如何结合在一起的。BlogRepository的构造函数允许您传递自己的网关和工厂对象,返回到您选择的默认实现。
要找到单个Blog,存储库首先从网关加载所有数据,并将其映射到使用工厂的对象。然后,Find方法返回与Id匹配的第一个Blog。诚然,您可能希望在“网关”对象上创建一个方法来返回单个记录,但是存储库也是实现缓存的好地方。
现在我们进入您感兴趣的部分:解析文件。
public class BlogFileGateway : IBlogGateway
{
private string filePath;
public BlogFileGateway(string filePath)
{
this.filePath = filePath;
}
public IList<IDictionary<string, object>> Load()
{
// Read entire file and return the parsed data
}
public void Create(int id, string name, string description)
{
// Append the new data to the file
}
public void Update(int id, string name, string description)
{
// Update the correct row within the file
}
public void Delete(int id)
{
// Delete the correct row within the file
}
}BlogFileGateway实现IBlogGateway接口。这就是打开、读取和解析文件的地方。如果您有一个通用文件格式,您的“网关”类可以创建另一个类的实例,负责解析文件中的每个记录。
为了更好的衡量,部落格工厂类:
public class BlogFactory : IBlogFactory
{
public Blog CreateInstance(IDictionary<string, object> data)
{
if (data == null)
return null;
Blog instance = new Blog();
UpdateInstance(data, instance);
return blog;
}
public void UpdateInstance(IDictionary<string, object> data, Blog instance)
{
instance.Id = int.Parse(data["id"].ToString());
instance.Name = data["name"].ToString();
instance.Description = data["description"].ToString();
}
}由于您将数据访问和映射与域模型分离开来,所以您可以从文件存储开始。转移到数据库存储需要编写一个新的网关类来访问数据库,以及一个新的工厂类将数据从数据库映射到您的Blog域模型。如果稍后您决定转向面向服务的体系结构,则只需编写另一个网关来调用web服务和另一个工厂即可。您可以从根本上改变或切换存储机制,而无需重构应用程序的主要部分。
@BartVanIngenSchenau在他的回答中说:
用于其他类型的数据访问(与第三方进行数据交换、读取/写入文件等)这些体系结构具有服务的概念,用于执行数据的传输,并在外部格式和业务层可以使用的东西之间进行转换。
(强调地雷)
使用Repository模式的优点是,调用web服务的代码不必存在于称为“服务”的应用程序的通用且经常被过度使用的层中。调用web服务发生在网关中。
让我们找到一个博客,更改一个值并更新它:
IBlogRepository repository = new BlogRepository();
Blog blog = repository.Find(3);
blog.Description = "Black and white, and read all over";
repository.Update(blog);稍后,您需要使用MySQL数据库以便编写BlogMySqlGateway和BlogMySqlFactory类,然后更改一行代码:
IBlogRepository repository = new BlogRepository(new BlogMySqlGateway(), new BlogMySqlFactory());
Blog blog = repository.Find(3);
blog.Description = "Black and white, and read all over";
repository.Update(blog);没有什么需要改变的了。稍后,您决定所有这些都需要生活在“云”中:
IBlogRepository repository = new BlogRepository(new BlogWebServiceGateway(), new BlogWebServiceFactory());
Blog blog = repository.Find(3);
blog.Description = "Black and white, and read all over";
repository.Update(blog);没有什么需要改变的了。
发布于 2015-10-09 04:30:35
在解析文件中的数据时,您可以在UserServicesLayer中这样做,如果要操作那些需要任何逻辑条件的数据,那么是时候调用BusinessLayer然后执行该层中的所有逻辑操作了,您的DataAccessLayer就像从数据库访问数据的桥,因此不建议在DataAccesLayer中提取数据。
希望这能有所帮助。
https://softwareengineering.stackexchange.com/questions/299435
复制相似问题