選單
GSS 技術部落格
在這個園地裡我們將從技術、專案管理、客戶對談面和大家分享我們多年的經驗,希望大家不管是喜歡或是有意見,都可以回饋給我們,讓我們有機會和大家對話並一起成長!
若有任何問題請來信:gss_crm@gss.com.tw
2 分鐘閱讀時間 (468 個字)

工廠模式(Factory Pattern)實際應用

unsplash-coding002

前陣子手頭上有個功能需求為:產生多張excel報表,ex:報表一、報表二、報表三…等。

這邊我們透過設計模式的工廠模式(Factory Pattern)來trytry …

首先,我們會有一個報表底層=>_Service,並提供一個Method=>CreateObject(),負責建立報表實體。而_Service就是所謂的報表工廠,不管報表怎麼實作的,皆會透過CreateObject()建立出一個報表實體(報表類)。 

public abstract class _Service
{
    //實作物件
    public static T CreateObject<T>(string TypeName, ReportParameterModel Parameter)
    {
        var theAssembly = typeof(T).Assembly;
        //取得類別
        Type theType = theAssembly.GetType($"ReportService.{TypeName}");
        if (theType == null)
            return default(T);
        return (T)Activator.CreateInstance(theType,
            BindingFlags.Instance | BindingFlags.Public, null, new object[] { Parameter },
            System.Globalization.CultureInfo.InvariantCulture, null);
    }
} 

但類似的報表有很多種。
所以再提供一個抽象類別=>_Xls,並且去繼承_Service,而這個抽象類別會提供產excel報表的Method=>CreateRPT(),負責處理產excel報表的過程。

public abstract class _Xls : _Service
{
    //報表參數
    public ReportParameterModel Parameter;
    internal Workbook excel;

    public _Xls(ReportParameterModel parameter)
    {
        Parameter = parameter;  
    }

    //創建報表  
    public virtual byte[] CreateRPT()
    {
        excel = new Workbook();
        Worksheet sheet = excel.Worksheets[0];
        CreateSheets();
        return Save();
    }
} 

產excel報表的過程中,會有多種工作表(sheet),而每個報表擁有的工作表(sheet)皆不同,故我們提供一個抽象的Method=>CreateSheets(),交由子類別去決定要建立哪張工作表。

public abstract class _Xls : _Service
{
    ......

    //建立工作表
    protected abstract void CreateSheets();
} 

產excel報表的過程中,除了工作表建立,可根據參數決定報表格式為何,才將報表下載下來,故提供method=> Save()。

public abstract class _Xls : _Service
{
    .......
    protected virtual byte[] Save()
    {
        using (MemoryStream ms = new MemoryStream())
        {
            if (Parameter.Type == "xlsx")
            {
                excel.Save(ms, SaveFormat.Xlsx);
            }
            else
            {
                excel.Save(ms, SaveFormat.ODS);
            }
            return ms.ToArray();
        }
    }
} 

前述提到會有各種工作表,故這邊我們會有一個工作表介面=>WorkSheet,並提供取得工作表名稱的Method=>GetSheetName()。

public interface WorkSheet 
{ 
    string GetSheetName(); 
} 

我們來實作一張工作表=>Report01Sheet,Report01Sheet會去繼承剛剛我們建立的工作表介面=>WorkSheet,並且實作GetSheetName()。

public class Report01Sheet : WorkSheet 
{ 
    public string GetSheetName(string name) 
    { 
        return name; 
    } 
} 

接下來,我們來實作報表類,報表一(Report01)會去繼承_Xls,並將複寫掉CreateSheets()。報表二也可以直接繼承報表一,再複寫掉CreateSheets(),若不複寫,則保有報表一的CreateSheets()。

public class Report01: _Xls  
{  
    public Report01(ReportParameterModel P) : base(P)  
    {  
    } 
    protected override void CreateSheets()  
    { 
       new Report01Sheet(Parameter.SheetName); 
    }  
}

public class Report02: Report01  
{  
    public Report02(ReportParameterModel P) : base(P)  
    {  
    } 
    protected override void CreateSheets()  
    { 
       new Report02Sheet(Parameter.SheetName); 
    }  
} 

最後,我們就可以來建立出報表類的實體,但至於是哪個報表類,會根據傳入的TypeName來交由工廠處理。
當今天傳入Report01,就會產生報表一的實體,若傳入Report02,就會產生報表二的實體,以此類推。
建立報表類的實體後,呼叫CreateRPT(),即可下載報表。
下面的例子,最後會下載報表二。

public FileResult DownloadReport(ReportParameterModel model)
{            
    //報表一
    var report = _Service.CreateObject<_Xls>("Report01", model);
    //報表二
    var report = _Service.CreateObject<_Xls>("Report02", model);
    return File(report.CreateRPT(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "報表");
} 

而以上的做法就是套用工廠模式的概念來實作,
何謂工廠模式?
工廠模式的實質是"定義一個建立物件的介面,但讓實現這個介面的類來決定實例化該類。工廠方法讓類別的實例化替代到子類中進行"。

也就是每張報表我們不需要知道他怎麼實作,但我們可透過工廠來決定他產生哪個報表類。


感謝大家收看,我們下集待續.....

你的 HTTPS 連線安全嗎? - 設定篇
每日小知識 #16 - Container 資安(7)

相關文章

 

評論

尚無評論
已經注冊了? 這裡登入
Guest
2024/05/18, 週六

Captcha 圖像