2011-02-26 68 views
2

我正在尝试使用ASP.NET和C#来制作简单的3层架构应用程序。 我走到循环依赖问题。 我在商业层有学生课。 我有那些方法来表现层的接口:3层架构问题

void SaveStudent(Student student); 
Student[] GetStudents(); 

这个貌似正常。

但我也从数据访问层接口,以业务与方法:

void InsertStudent(Student student); 
Student[] ReadAllStudents(); 

问题是与学生类。 由于我的业务层依赖于DAL,因此无法将数据访问层的业务层引用。我知道DAL不应该依赖于业务层。但不知道如何解决这个问题。

我应该如何传递数据呢?

如果我将学生类放在DAL中,那么我的表示层将被强制依赖于不好的数据访问层。

我从来没有尝试过使用3层架构。

如何解决这个问题? 如果需要,可以随意更改我的界面方法。

回答

4

这个问题通常是通过将你的Student类放置在一个单独的Models集合(称之为你喜欢的)中来解决的,它将在所有图层之间共享。在大规模的n层体系结构中,这些类一般只包含数据,通常被称为数据转换对象(DTO)。作用于这些对象的任何业务逻辑都将保存在通常作为服务公开的业务层(BL)中(即WCF)。该服务只是一个中介,即使所有代码都坐在同一台机器上,甚至在同一个进程中,也可以用这种方式进行设计。至少要在组件级别分离您的顾虑(UI,业务层,DTO,DAL)。

在您的情况下,GetStudents方法将暴露在业务层服务上,并返回Student DTO。业务层将持有对其将调用InsertStudent的数据访问层(DAL)的引用。同样,正如我所说的,DAL和BL都有对模型组件的引用,但最重要的是DAL不依赖于BL。

客户端 - >业务层服务 - >数据访问

< ------------------学生(DTO)------ ------------>

+0

@达斯刘易斯:这看起来像对我来说是最好的答案,我明白如何做到这一点。 :) 谢谢达斯刘易斯。 – Vajda 2011-02-26 12:54:26

+0

所以你会在模型中有一名学生,而在DTO中有另一名学生,都是为了建筑的纯净性?对不起,我认为这是最糟糕的答案。不得不维护两个并行的对象层次来表达相同的想法是一个不稳定的原因。不幸的是,这也很常见。 – duffymo 2011-02-26 13:16:44

+0

@duffymo这种方法根本没有学生实体的重复。为什么您认为在这种情况下需要区分模型和DTO域? – 2011-02-26 13:23:52

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(); 
    } 
} 
+0

我知道,但如何实现这一目标?添加代码 – Vajda 2011-02-26 12:33:36

+0

;现在应该很简单 – Cosmin 2011-02-26 12:36:44

+0

好吧,所以学生类去DAL,我应该在演示中使用哪个类?由于演示文稿根本不应该了解DAL。你能告诉我什么看起来像两个接口? – Vajda 2011-02-26 12:38:11

2

n-tier架构的关键概念是n-th层只知道的n+1-th层。因此,您的用户界面将调用业务逻辑,业务逻辑将调用数据访问层。

+0

我知道,但如何做到这一点?你能告诉我一些例子吗? – Vajda 2011-02-26 12:34:48

1

您应该在演示文稿层和持久层之间放置一个服务。持久层调用服务,该服务与您的模型和持久层交互以完成请求。

三层体系结构是客户端/服务器编程的产物。面向服务的架构是一个更现代的问题。它在演示文稿和其他文件之间插入一个服务层。有几个好处:

  1. 它使演示文稿与其他任何东西都分开,所以您可以随意更改或添加新的演示文稿。
  2. 它将业务逻辑封装为可重用组件,而不是将其锁定在演示文稿中。
  3. 它使安全性,日志记录等变得更加清晰,因为您可以使用面向方面的编程来修饰具有交叉担忧的服务调用。

这里是如何的界面看起来可能会在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;服务使用模型和持久性包来完成请求,这些请求应映射到用例。

您的演示文稿根本不需要知道模型对象。发送XML或JSON或其他一些序列化格式,然后演示文稿就可以呈现它。

+0

你能告诉我这个微型问题吗? :) – Vajda 2011-02-26 12:40:45

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 ... 
} 
1

您需要引入一个名为Model的图层。该图层仅将Student类定义为数据对象。 (在这一层没有保存或获取方法)。

模型图层可以在它自己的项目(以及它自己的dll)中。现在在所有层(Presentation,Business和DA)中引用dll。使用Student类型仅保存数据元素。

在业务层中,引用DA层并拥有一个具有SaveStudent方法的类Student。在DA层中,仅引用Model层并实现保存学生方法。 (注意:这只能说明该层,这些层应该具有的类,最好的类应该执行旨在实现这一目的的接口,但是这本身不是你的问题的一部分)

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 
    } 

} 

}