我正在尝试使用ASP.NET和C#制作简单的3层架构应用程序。 我走向循环依赖的问题。 我在商务层有学生班。 我有一个使用这些方法的表示层接口:
void SaveStudent(Student student);
Student[] GetStudents();
这看起来不错。
但是我还使用这些方法从Data Access层到Business的接口:
void InsertStudent(Student student);
Student[] ReadAllStudents();
问题在于学生班。 由于我的业务层依赖于DAL,因此我无法从数据访问层引用业务层。我知道DAL不应该依赖于业务层。但不知道如何解决这个问题。
我应该如何传递数据?
如果我将Student类放到DAL那么我的表示层将被强制依赖于数据访问层,这是不好的。
我之前从未尝试过制作3层架构。
如何解决这个问题? 如果需要,可以随意更改我的界面方法。
答案 0 :(得分:4)
这个问题通常通过将您的Student类放在一个单独的模型程序集(称之为您喜欢的程序)中来解决,该程序集将在所有层中共享。在大规模的n层体系结构中,这些类通常只包含数据,通常称为数据转换对象(DTO)。作用于这些对象的任何业务逻辑将保存在业务层(BL)中,该业务层通常作为服务公开(即WCF)。该服务只是一个中介,即使所有代码都位于同一台机器甚至同一个进程中,您也可以通过这种方式进行设计。您至少需要在程序集层面分离您的问题(UI,业务层,DTO,DAL)。
在您的情况下,GetStudents方法将在业务层服务上公开,并将返回Student DTO。业务层将保存对数据访问层(DAL)的引用,它将调用InsertStudent。我再次说过DAL和BL都有对模型程序集的引用,但最重要的是DAL没有对BL的依赖。
客户 - >业务层服务 - >数据访问层
< ------------------学生(DTO)------------------>
答案 1 :(得分:2)
n-tier
架构中的关键概念是n-th
层只知道n+1-th
层。因此,您的用户界面将调用业务逻辑,业务逻辑将调用数据访问层。
答案 2 :(得分:1)
您不应该从DAL调用BLL(业务逻辑层),反之亦然。
// Will contain details about your UI - taking data from text fields, etc
// and passing it to the business object
class Student_UI
{
Student_BL _blObject = new Student_BL();
void SaveStudent()
{
Student student = new Student();
// Get student details from UI...
_blObject.SaveStudent(student);
}
DisplayStudents()
{
Student[] students = _blObject.GetStudents();
// display students...
}
}
class Student_BL
{
Student_DAL _dalObject = new Student_DAL();
void SaveStudent(Student student)
{
_dalObject.InsertStudent(student);
}
Student[] GetStudents()
{
return _dalObject.ReadAllStudents();
}
}
答案 3 :(得分:1)
您应该在演示文稿层和持久层之间放置 服务 。持久层调用服务,该服务与模型和持久层交互以完成请求。
三层体系结构是客户端/服务器编程的工件。面向服务的体系结构是对问题的更现代化的解决方案。它在演示文稿和其他演示文稿之间注入服务层。有几个好处:
以下是Java中界面的外观 - 翻译成您选择的语言:
package model;
public class Foo
{
private Long id;
private String name;
}
package service;
public interface FooService
{
Foo findFoo(Long id);
List<Foo> findAllFoos();
void saveAllFoos(List<Foo> foos);
void delete(Foo foo);
}
package persistence
public interface GenericDao<K, V>
{
List<V> find();
V find(Long id);
K save(V value);
List<K> save(List<V> values);
void update(V value);
void delete(V value);
}
所以presentation->service->persistence
; service使用模型和持久性包来完成请求,这些请求应映射到用例。
您的演示文稿根本不需要了解模型对象。发送类似XML或JSON或其他一些序列化格式的内容,演示文稿只是呈现它。
答案 4 :(得分:1)
您需要再引入一个名为Model的图层。该层将Student类定义为仅数据对象。 (此图层中没有保存或获取方法)。
Model层可以在自己的项目中(因此它自己的dll)。现在在所有层(Presentation,Business和DA)中引用dll。使用Student类型仅保存数据元素。
在Business层中,引用DA层并使用具有SaveStudent方法的Student类。在DA层中,仅引用Model层并实现save student方法。 (注意,这只显示了这些层应该具有的层和类,理想情况下,类应该实现为此目的而设计的接口,但这本身不是您问题的一部分)
namespace Model{
class Student
{
public string Name { get; set; }
public String Address { get; set; }
// more student properties here ..
// No methods like SaveStudent in this class , thats up into the business layer
public bool IsValid(){ // validate the student here }
}
}
namespace Business{
class Student
{
// call this method from your Presentation layer
public void SaveStudent(Model.Student student)
{
if (student.IsValid())
{
DataAccess.StudentDAO student = new DataAccess.StudentDAO();
student.SaveStudent(student);
}
else
{
throw new ApplicationException("Invalid student");
}
}
}
}
namespace DataAccess{
class StudentDAO
{
public void SaveStudent(Model.Student student)
{
// impl here to save a student informatin to a
// persistent storage
}
}
}
答案 5 :(得分:0)
下面的代码说明了服务(或业务逻辑)层提供注入存储库的方法的关注点。
这可确保StudentService不知道学生的持久方式和位置。它还使您能够单独测试存储库和服务的行为。
如果您使用的是IoC方法(例如StructureMap或Unity),您可以使用容器进行注射。
public class StudentService
{
private IStudentRepository _studentRepository;
public StudentService(IStudentRepository studentRepository)
{
_studentRepository = studentRepository;
}
}
public interface IStudentRepository
{
void Save(Student student);
Student[] GetStudents();
}
public class StudentRepository : IStudentRepository
{
... implement the methods defined in the interface ...
}