有些時候,我們在進行 C# 程式設計的時候,需要產生一些物件,但是,需要由哪個具體實作類別來產生,並不希望在設計時期來指定,而是在應用程式執行的時候,依據當時應用程式的設定參數,來進行決定要由哪個類別來產生特定介面的物件。在這篇文章中,我們將會設計一個 靜態工廠模式 Static Factory Pattern 類別,建立起一個鬆散耦合的程式。
當我們呼叫靜態工廠方法的 StaticFactory.GetMessage() 方法的時候,會依據 app.config 這個設定檔案內容定義的資料,產生出一個型別為 IMessage 的具體實作類別物件;在這個範例中,我們要產生一個可以發送訊息通知的物件,將所們指定的訊息發送出去,我們設計了介面 IMessage,並且有兩個類別 SMSMessage (使用簡訊方式發送) 與 EMailMessage (使用電子郵件方式發送) 皆實作這個介面,因此,我們在主程式端,透過靜態工廠模式類別,幫助我們產生一個 IMessage 的實作物件,讓我們可以傳送出訊息出去。
不過,我們在靜態工廠模式類別中,並沒有指定要由哪個類別來產生這個物件,而是我們會讀取 app.config 這個 XML 檔案的
appSettings
裡面的定義內容,找到 IMessage 的設定值,這個設定文字的內容是會指定類別的在組件中定義名稱,我們使用這個字串與 Type.GetType 方法,幫助我們產生出指定的型別物件,透過 Activator.CreateInstance 方法,可以產生出該類別的執行個體了
在這裡,我們建立一個 .NET Framework 主控制台應用專案 AccessConfigurationManager
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.Linq;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AccessConfigurationManager
{
public interface IMessage
{
void Send(string message);
}
public class SMSMessage : IMessage
{
public void Send(string message)
{
Console.WriteLine($"簡訊已經送出 : {message}");
}
}
public class EMailMessage : IMessage
{
public void Send(string message)
{
Console.WriteLine($"郵件已經送出 : {message}");
}
}
public class StaticFactory
{
public static IMessage GetMessage()
{
// 這裡要加入 System.Configuration 組件參考
NameValueCollection appSettings = ConfigurationManager.AppSettings;
string fooValue = appSettings["IMessage"] ;
Type fooType = Type.GetType(fooValue);
IMessage fooObject = Activator.CreateInstance(fooType) as IMessage;
return fooObject;
}
}
class Program
{
static void Main(string[] args)
{
#region 取得指定完整的類型名稱
var foo = typeof(SMSMessage);
var bar = foo.AssemblyQualifiedName.ToString();
Console.WriteLine(bar);
#endregion
IMessage messageObject = StaticFactory.GetMessage();
messageObject.Send("我已經動態產生具體實作物件了");
Console.WriteLine("Press any key for continuing...");
Console.ReadKey();
}
}
}
緊接著,我們在該專案中,找到根目錄下的 app.config 檔案,將其打開,並且在 Configuration 節點內,建立一個 appSettings 節點,我們將會在這個節點內,建立一個 IMessage 鍵值,他的值為 AccessConfigurationManager.SMSMessage, AccessConfigurationManager 。這個字串將會表示在 AccessConfigurationManager 組件內的 AccessConfigurationManager.SMSMessage 類別。若您想要得到某個類別的完整組件識別字串,可以參考這篇文章 指定完整的類型名稱 與底下程式碼用法。
#region 取得指定完整的類型名稱
var foo = typeof(SMSMessage);
var bar = foo.AssemblyQualifiedName.ToString();
Console.WriteLine(bar);
#endregion
底下是我們修正後的 app.config 設定內容
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
<appSettings>
<add key="IMessage" value="AccessConfigurationManager.SMSMessage, AccessConfigurationManager"/>
</appSettings>
</configuration>
現在,可以執行這個測試專案,我們將會看到我們產生了類別 SMSMessage 這個類別的執行個體
AccessConfigurationManager.SMSMessage, AccessConfigurationManager, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
簡訊已經送出 : 我已經動態產生具體實作物件了
Press any key for continuing...
假設現在客戶有變更需求產生,所有的訊息通知,將不再使用簡訊方式發送,而要改用電子郵件方式來發送;在以往,我們需要修改我們的原始程式碼,但是這樣做,有可能會產生更多的 bug (尤其是在大型、多人開發的專案上)。不過,經過我們這樣的設計模式,我們僅需要修正 app.config 這個設定檔案中的 IMessage 值,重新執行一次
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
<appSettings>
<add key="IMessage" value="AccessConfigurationManager.EMailMessage, AccessConfigurationManager"/>
</appSettings>
</configuration>
現在,我們將會看到我們產生了類別 EMailMessage 這個類別的執行個體
AccessConfigurationManager.SMSMessage, AccessConfigurationManager, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
郵件已經送出 : 我已經動態產生具體實作物件了
Press any key for continuing...
關於 Xamarin 在台灣的學習技術資源
歡迎加入 Xamarin 實驗室 粉絲團,在這裡,將會經常性的貼出各種關於 Xamarin / Visual Studio / .NET 的相關消息、文章、技術開發等文件,讓您可以隨時掌握第一手的 Xamarin 方面消息。
歡迎加入 Xamarin.Forms @ Taiwan,這是台灣的 Xamarin User Group,若您有任何關於 Xamarin / Visual Studio / .NET 上的問題,都可以在這裡來與各方高手來進行討論、交流。
Xamarin 實驗室 部落格 是作者本身的部落格,這個部落格將會專注於 Xamarin 之跨平台 (Android / iOS / UWP) 方面的各類開技術探討、研究與分享的文章,最重要的是,它是全繁體中文。
Xamarin.Forms 系列課程 想要快速進入到 Xamarin.Forms 的開發領域,學會各種 Xamarin.Forms 跨平台開發技術,例如:MVVM、Prism、Data Binding、各種 頁面 Page / 版面配置 Layout / 控制項 Control 的用法等等,千萬不要錯過這些 Xamarin.Forms 課程