簡單架構:反射實現抽象工廠+IDAL接口完全獨立DAL


一、普通架構中存在的問題 

StudentDB數據庫,包含一張StudentInfoTB表,結構如下:

s_id int primary key identity(1,1),
s_name Nvarchar(10) not null,
s_age int check(s_age >10 and s_age<30),
s_sex bit not null

先來看一下普通的架構的問題所在:

調用關系:

dal層代碼只是通過SqlHelper簡單的操作一下數據庫,就不展示了。

StudentInfo的bll層代碼,實例化了一個dal層對象,並且每個方法返回對應的方法:

private StudentInfoADODal dal = new StudentInfoADODal();
public List<StudentInfoModel> Select()
{
    return dal.Select();
}

public int Update(StudentInfoModel siModel)
{
    return dal.Update(siModel);
}

public int Delete(int id)
{
    return dal.Delete(id);
}

public int Add(StudentInfoModel siModel)
{
    return dal.Add(siModel);
}

public StudentInfoModel Get(int id)
{
    return dal.Get(id);
}
View Code

ui層調用:

static void Main(string[] args)
{
    Display();
    Console.ReadKey();
}

static void Display()
{
    //實例化bll層對象
    StudentInfoBll bll = new StudentInfoBll();
    //接收返回值
    List<StudentInfoModel> lstModel = bll.Select();
    //輸出標題
    Console.WriteLine($"編號\t姓名\t年齡\t性別");
    //循環輸出
    foreach (StudentInfoModel  item in lstModel)
    {
        Console.WriteLine($"{item.s_id}\t{item.s_name}\t{item.s_age}\t{item.s_sex}");
    }
}

輸出:

 

一切看起來都沒什么問題,可是如果后續邏輯復雜起來了,並且Dal層對象有變動的話,我們是不是需要在Bll層修改實例化的Dal層對象,而且一但更改,所有位置的Dal層對象都會修改,現在代碼很少,東西也不復雜,可是如果代碼復雜了,修改的話就不是太方便了。

首先我們應該想到的是工廠模式,因為如果Dal層有變動的話,我們只需要修改工廠模式中返回的對象就行了,但是如果使用簡單工廠模式的話,返回值是個問題,Dal層改變的話,返回值肯定也會發生改變,到時候還是要對bll層接收對象修改類型。

二、抽象工廠+IDal

所以我們應該考慮使用抽象工廠,既然要用抽象工廠,那么就必須有一個具體的父類或者接口,但是Dal層並沒有繼承任何父類或實現任何接口(Object除外),所以我們應該抽象出一個IDal層,使得所有的Dal層都要去實現IDal層,然后用IDal層的接口作為返回值,返回給Bll層,后續如果在要修改Dal層的話,只要Dal層實現了IDal層我們是不是就不用在對Bll層做任何修改了。

接下來先創建IDal層:

然后抽象出IStudentInfoDal接口:

public interface IStudentInfoDal
{
    List<StudentInfoModel> Select();
    int Update(StudentInfoModel siModel);
    int Delete(int id);
    int Add(StudentInfoModel siModel);
    StudentInfoModel Get(int id);
}

StudentInfoADODal層實現IStudentDal接口:

下面就是使用工廠模式來進行創建對象,先創建工廠層和DalFactory類:

public class DalFactory
{
    public static IStudentInfoDal CreateStudentInfoInstance()
    {
        return new StudentInfoADODal();
    }
}

Bll層調用的話直接聲明接口,然后通過工廠模式來獲取Dal層對象:

private IStudentInfoDal dal = DalFactory.CreateStudentInfoInstance();

這下如果后續需要更改的話,直接就更改工廠模式這一個地方就行了,其他地方就不用做更改了。

現在看一下調用關系,箭頭是引用關系

 

可以發現,Dal層並沒有做到完全獨立起來,Factory層還是在引用Dal層,更換數據庫的話,還是要重新添加引用,重新修改工廠模式中的代碼。小項目不分層都是可以的,如果項目很復雜,做任何事情之前都要考慮周到,任何細節都要處理好,所以就想辦法把Dal層完全獨立起來

三、反射+App.config實現抽象工廠

 反射就是能夠動態加載程序集,不需要添加對程序集的引用,就可以獲取程序集內部的結構(屬性、方法),可以實現動態創建對象,調用對象的方法,為屬性賦值等操作。所以,在創建Dal層對象時,我們可以考慮使用反射來創建。

反射所在命名空間:System.Reflection;  其實就是先將dll文件給加載到Assembly對象中,然后通過Assembly對象創建dll文件中的對象(反射還有其他的幾個常用的對象Type、Activator、PropertyInfo...)

使用反射創建dal層對象:

public static IStudentInfoDal CreateStudentInfoInstance()
{
    //使用Assembly來加載程序集 
    Assembly assembly = Assembly.Load("CKKA.ADODal");
    //通過assembly對象來創建一個StudentInfoADODal實例
    //必須是完整的類型名稱         類型所在命名空間+“.”+類名
    Object siDal = assembly.CreateInstance("CKKA.ADODal.StudentInfoADODal");
    return siDal as IStudentInfoDal;
}

然后右鍵CKKA.ADODal-->屬性-->最左側生成-->下方輸出路徑改為Ui/bin/debug或者Ui/bin(具體可以自己打開文件夾下看那個目錄下有dll文件),詳情看這篇帖子https://www.cnblogs.com/ckka/p/11331037.html

現在運行該程序是可以反射成功的

我們把將抽象工廠再次改造一下,將CKKA.ADODal和后綴ADODal寫在App.config的appSettings節點下(web項目寫在web.config)

<add key="AssemblyName" value="CKKA.ADODal"/>
<add key="Suffix" value="ADODal"/>

抽象工廠改進為(需要為Factory添加System.Configuration程序集和命名空間的引用):

public class DalFactory
{
    //從配置文件中讀取AssemblyName(程序集名稱)和Suffix(Dal層擴展名)
    private static String AssemblyName = ConfigurationManager.AppSettings["AssemblyName"];
    private static String Suffix = ConfigurationManager.AppSettings["Suffix"];

    //每個方法都調用此方法來創建對象
    private static Object CreateInstance(String TypeName)
    {
        return Assembly.Load(AssemblyName).CreateInstance(TypeName);
    }
    
    public static IStudentInfoDal CreateStudentInfoInstance()
    {   
        //拼接類型名稱
        String TypeName = $"{AssemblyName}.StudentInfo{Suffix}";
        //創建實例
        return CreateInstance(TypeName) as IStudentInfoDal;
    }
    
}

以后我們如果需要更換數據庫的話,只需要修改配置文件,操作數據庫的Dal實現IDal接口,並且bin目錄下有dll文件就行了,不需要更改任何代碼。

由於沒有其他數據庫,我們就用EF操作數據庫來測試一下:

將CKKA.EFDal的生成路徑更改一下,然后修改配置文件為:

然后運行:

可以發現,完全不用改任何代碼,就可以做到更換一整個Dal或者數據庫,最終調用結構為:

如果我哪里寫的有問題或者我說的不夠清楚或者你有疑問的話,歡迎留言

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM