1. 程式人生 > >簡單架構:反射實現抽象工廠+IDAL介面完全獨立DAL

簡單架構:反射實現抽象工廠+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或者資料庫,最終呼叫結構為:

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