[.NET] : Provider Pattern
前言 :
在面向对象的程序开发设计上,我们常常强调重用与抽换 : 重用核心的程序代码,抽换特定的模块。
但是大多的面向对象的书,只有介绍重用与抽换的理论,并没有介绍实做的时候该怎么写。
因为实际开发系统,要完成重用与抽换。牵扯到系统设计、动态加载、Config管理......等等方方面的知识。
真的要解释起来,需要的篇幅会是很大一篇。
本篇的文章跳过这些复杂的理论面,逐步解说如何实做微软提供的Provider Pattern来实现对象的抽换。
Provider Pattern提供了,使用App.config或是web.config来做储存装置,并且实做了对象抽换的功能。
依照本篇的模块去做面向对象开发设计的基础,可以比较轻松架构出类似 [Application Architecture] : 数据存取层 的程序。
IDisplayProvider :
程序的开始先从提供抽换的接口看起。
IDisplayProvider是我们范例里提供抽换的接口。
AAADisplayProvider 、BBBDisplayProvider是实做抽换界面的物件。
这两个对象必须是继承System.Configuration.Provider.ProviderBase及IDisplayProvider。
public interface IDisplayProvider { void Show(); } public class AAADisplayProvider : ProviderBase, IDisplayProvider { public void Show() { Console.WriteLine("This is AAA."); } } public class BBBDisplayProvider : ProviderBase, IDisplayProvider { public void Show() { Console.WriteLine("This is BBB."); } }
配置文件 :
这边来看看.config内部的设定
<configuration> <configSections> <section name="displayProvider" type="ConsoleApplication1.DisplayProviderSection, ConsoleApplication1" /> </configSections> <displayProvider defaultprovider="AAA"> <providers> <add name="AAA" type="ConsoleApplication1.AAADisplayProvider, ConsoleApplication1" /> <add name="BBB" type="ConsoleApplication1.BBBDisplayProvider, ConsoleApplication1" /> </providers> </displayProvider> </configuration>
这边比较不同的,是底下这一段配置文件。
当 defaultProvider设定为AAA的时候,我们在后续的程序代码会取得ConsoleApplication1这个Dll里面的 ConsoleApplication1.AAADisplayProvider对象来使用。
当 defaultProvider设定为BBB的时候,我们在后续的程序代码会取得ConsoleApplication1这个Dll里面的 ConsoleApplication1.BBBDisplayProvider对象来使用。
<displayProvider defaultprovider="AAA"> <providers> <add name="AAA" type="ConsoleApplication1.AAADisplayProvider, ConsoleApplication1" /> <add name="BBB" type="ConsoleApplication1.BBBDisplayProvider, ConsoleApplication1" /> </providers> </displayProvider>
关于App.config或是web.config的设定方式可以参考小朱写的 : [ASP.NET]撰写自己的 Configuration 区段。
使用范例 :
这边来看看实际使用的范例
依照配置文件的不同,程序建立的对象就会不同。同样的程序代码在画面上显示的数据会不一样。
当 defaultProvider设定为AAA的时候,画面显示 This is AAA.
当 defaultProvider设定为BBB的时候,画面显示 This is BBB.
class Program { static void Main(string[] args) { IDisplayProvider provider = DisplayProviderFactory.Create(); provider.Show(); Console.ReadLine(); } }
DisplayProviderSection :
DisplayProviderSection主要是定义配置文件的格式。
public class DisplayProviderSection : ConfigurationSection { public const string SectionName = @"displayProvider"; [ConfigurationProperty("providers", IsDefaultCollection = true)] public ProviderSettingsCollection Providers { get { return (ProviderSettingsCollection)base["providers"]; } } [ConfigurationProperty("defaultProvider")] public string DefaultProvider { get { return (string)base["defaultProvider"]; } set { base["defaultProvider"] = value; } } }
DisplayProviderFactory :
DisplayProviderFactory是实际读取配置文件数据,并建立对象的地方。
public class DisplayProviderFactory { public static IDisplayProvider Create() { return CreateProvider(DisplayProviderSection.SectionName); } private static IDisplayProvider CreateProvider(string sectionName) { DisplayProviderSection section = (DisplayProviderSection)ConfigurationManager.GetSection(sectionName); if (section == null) throw new ConfigurationErrorsException(string.Format("Can't find Section : {0}.", sectionName)); IDisplayProvider provider = (IDisplayProvider)InstantiateProvider(section.Providers[section.DefaultProvider], typeof(IDisplayProvider)); if (provider == null) throw new ConfigurationErrorsException(string.Format("Can't find Provider : {0}.", section.DefaultProvider)); return provider; } private static ProviderBase InstantiateProvider(ProviderSettings providerSettings, Type providerType) { Type settingsType = Type.GetType(providerSettings.Type); if (settingsType == null) throw new ConfigurationErrorsException(String.Format("Could not find type: {0}", providerSettings.Type)); if (!providerType.IsAssignableFrom(settingsType)) throw new ConfigurationErrorsException(String.Format("Provider '{0}' must subclass from '{1}'", providerSettings.Name, providerType)); ProviderBase provider = Activator.CreateInstance(settingsType) as ProviderBase; provider.Initialize(providerSettings.Name, providerSettings.Parameters); return provider; } }
期許自己~
能以更簡潔的文字與程式碼,傳達出程式設計背後的精神。
真正做到「以形寫神」的境界。