前陣子手頭上有個功能需求為:產生多張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", "報表");
}
而以上的做法就是套用工廠模式的概念來實作,
何謂工廠模式?
工廠模式的實質是"定義一個建立物件的介面,但讓實現這個介面的類來決定實例化該類。工廠方法讓類別的實例化替代到子類中進行"。
也就是每張報表我們不需要知道他怎麼實作,但我們可透過工廠來決定他產生哪個報表類。
感謝大家收看,我們下集待續.....
When you subscribe to the blog, we will send you an e-mail when there are new updates on the site so you wouldn't miss them.
評論