2011-02-26 91 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 
    } 

} 

}