zoukankan      html  css  js  c++  java
  • Provider模式(转载)

    [原文:The .NET 2.0 Framework Provider Pattern]

    [中文名:.NET 2.0Provider模式]

    [出处:http://www.c-sharpcorner.com/]

    [作者:Matthew Cochran]

    [翻译:极地银狐.NET]

    第一部分: Provider模式统览

    Provider设计模式是在.NET 1.1 framework中被首次介绍到,特别是在ASP.NET快速入门中,以及后来在ASP.NET Whidbey中作为membership management provider API被正式化。它的主要目的在于为一个API进行定义和实现的分离。这样就通过核心功能的灵活性和易于修改的特点使得API具有灵活性。

    MSDN上能找到关于此模式在.NET 1.1 Framework的更多信息:

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspnet/html/asp02182004.asp

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspnet/html/asp02182004.asp

    Provider设计模式基本上是由GOF的两个设计模式溶合而成的:strategyabstract factoryAPI定义好,其功能通过strategy模式变异而来,是“可插(拔)”的,而功能被加载进内存则是通过大致地一个abstract factory设计模式而实现的。

    以下是此部分基本概要,以及它们如何互交。

    <!--[if !supportLists]-->1. <!--[endif]-->API Class:这是一个通过静态方法定义和暴露所需功能的类,在API Class中并没有具体的实现。此类保持一个对Application Provider Base类的引用,这个base类会对API中的功能进行基本的包装(Wrap)。

     

    本文中的API Class是一个商店(Store)我们可以从中买东西,如Coke(可乐)Snickers(译者:不知道这是啥。),还有在吃Snicker和喝Coke时所要的diet pills(减肥药)。

    <!--[if !vml]-->
    <!--[endif]-->

    我们的类包括以下几部分:

    A:我们有基本的API用于存放货物AddProductToStock,还有如GetProductPriceGetProductStockCount以及RemoveProductFromStock等核心方法。

    B:我们有个叫Initialize()的方法用于从系统配置文件中加载已有的具体商店。

    C:我们有所有可用Provider的引用。

    D:我们有一个默认Provider的引用,此Provider已被包装。

    一旦实例化,所有对这个API类的请求都会一个一个地转给默认的Provider

    <!--[if !supportLists]-->2. <!--[endif]-->Provider Base Class:这是一个内部抽象类,位于System.Configuration.Provider命名空间,用于定义一个ProviderInitialize()方法用于从配置文件中获取必要的信息来构建具体的Provider。我们在自己实现这个抽象类的时候要记的重写Initialize()方法。

    <!--[if !vml]-->
    <!--[endif]-->

    <!--[if !supportLists]-->3. <!--[endif]-->Application Provider Base:这是一个从ProviderBase类继承来的一个抽象类,同时也是API类的一个“镜像”,通过在API中所暴露的方法来为父类定义抽象方法并在父类中实现。

    在我们的应用程序中我们把这个类叫做“StoreProvider”,请注意这个Store Provider是如何定义在Store类中已有的方法,同时从ProviderBase类继承。

     

    <!--[if !supportLists]-->4. <!--[endif]-->Concrete ProviderApplication Provider Base中所定义的方法在这个类中实现。Concrete Provider为了从配置文件中读取信息而会重写Initialize()方法

    这四个类是实现Provider模式所必须的。其它的类则是用来定义一个Provider能提供什么东西(在本文中,是一个Product类)或是在以后为这些对象提供服务的工具类,或是用于管理程序配置文件。

     

    <!--[if !vml]-->
    <!--[endif]-->

    这些东西看起来有点晕,不过当你看到一个请求传给Store类后再转交给一个StoreProvider的引用,由具体的CornerStoreProvider去完成时,你就知道这几个“齿轮”是如何配合的了。

    第二部分:细节,细节,还是细节~

    现在我们已经大概了解了一下基础了。好,再让我们把程序深入一些。首先我们构建一个API用于和商店以及商店中的货物(或是叫产品)互交。

    看看这个货物(或是叫产品,下同)类:

    <!--[if !vml]-->
    <!--[endif]-->

    这个类并不是Provider模式的一部分,我们只是用它来把数据搬进搬出而已。我们为每个货物定义名字和批发价。每个商店自己的货物都有自己不同的售价,所以我们还要计算这些货物的零售价。我也添加了一个静态方法来得到所有可用的货物:GetProducts() Initialize()

    Store类定义了核心方法给我们(客户端),从storeproducts体现。

    <!--[if !vml]-->
    <!--[endif]-->

    Store Provider暴露了我们早先提到的抽象类中的方法

    <!--[if !vml]--><!--[endif]-->

    CornerStoreProvider是我们Store Provider类的具体实现。

    <!--[if !vml]--><!--[endif]-->

    VendingMachineStoreProviderStore Provider类的另一具体实现。

    <!--[if !vml]-->
    <!--[endif]-->

    Initialize()是每一个具体类都要实现的一个有趣方法。这个方法存在于ProviderBase中,但由ProvidersHelper调用。以下方法重写ProviderBase中的Initialize并从配置文件的<Store>节点中读取所需要的信息:

     1 <?xml version="1.0" encoding="utf-8" ?>
     2 
     3 <configuration>
     4 
     5   <configSections>
     6 
     7     <section name="store" type="ProviderSample.StoreProviderConfigurationSection,
     8 
     9       ProviderSample, Version=1.0.0.0,
    10 
    11       Culture=neutral,PublicKeyToken=null" />
    12 
    13   </configSections>
    14 
    15   <store defaultProvider="CornerStoreProvider">
    16 
    17     <providers>
    18 
    19       <add name="VendingMachineStoreProvider"
    20 
    21            type="VendingMachineStoreProvider"
    22 
    23            Coke="0.75"
    24 
    25            Snickers="0.5"
    26 
    27            Diet_Pills="1.25"
    28 
    29            ></add>
    30 
    31       <add name="CornerStoreProvider"
    32 
    33            type="CornerStoreProvider"
    34 
    35            Coke="0.70"
    36 
    37            Snickers="0.65"
    38 
    39            Diet_Pills=".80"
    40 
    41            ></add>
    42 
    43     </providers>
    44 
    45   </store>
    46 
    47 </configuration>

     

     1 public override void Initialize(string name, NameValueCollection config)
     2 
     3 {
     4 
     5     if (string.IsNullOrEmpty(name))
     6 
     7         name = "CornerStoreProvider";
     8 
     9  
    10 
    11     if (null == config)
    12 
    13         throw new ArgumentException("config parameter can not be null");
    14 
    15  
    16 
    17     if (string.IsNullOrEmpty(config["description"]))
    18 
    19     {
    20 
    21         config.Remove("description");
    22 
    23         config.Add("description""A Corner store from which to get a product");
    24 
    25     }
    26 
    27  
    28 
    29     base.Initialize(name, config);
    30 
    31  
    32 
    33     m_inventory.Clear();
    34 
    35  
    36 
    37     foreach (Product p in Product.GetProducts())
    38 
    39     {
    40 
    41         if (string.IsNullOrEmpty(config[p.Name]))
    42 
    43         {
    44 
    45             m_markup.Add(p, 0);
    46 
    47         }
    48 
    49         else
    50 
    51         {
    52 
    53             m_markup.Add(p, Convert.ToDouble(config[p.Name]));
    54 
    55         }
    56 
    57     }
    58 }

    System.Web.Configuration命名空间中有一个ProvidersHelper类,由于本示例是一个windows程序,所以我用反射重写了这个工具类,这样就不用引入整个 System.Web.Configuration命名空间了。ProvidersHelper是用于实例化具体Provider类以及从配置文件中读取所需要的信息,如果你想在WEB应用中实现Provider模式,使用System.Web.Configuration.ProvidersHelper来代替。(接口是相同的,所以很容易换过去。)

    <!--[if !vml]-->
    <!--[endif]-->

    同样,有一个StoreProviderConfigurationSection继承自

    System.Configuration.ConfigurationSection

    用来从配置文件中获取Providers default provider的配置信息。

    <!--[if !vml]-->
    <!--[endif]-->

     

    第三部分:执行

    为了使用我们的API,我们要对静态的Store类进行方法调用,在本次示例中如果我们默认的provider存有产品,我们可以通过API类(Store)提供的方法使用默认provider

     

     1 // Get some coke
     2 
     3 Product p1 = Product.GetProduct("Coke");
     4 
     5  
     6 
     7 // find out the cost
     8 
     9 double cost = Store.GetProductPrice(p1);
    10 
    11  
    12 
    13 // get it from the store
    14 
    15 Store.RemoveProductFromStock(p1);  // remove from inventory  

    如果我们想要另一个默认的Provider,我们可以修改配置文件,把其它已实现此API的类加载到内存。跑跑这个示例项目,修改配置文件中的值来看看价格是否发生变化。

    <storedefaultProvider="CornerStoreProvider">

    这个就不只可以有不同的价格了,它还意味着可以有完全不同的功能。

    第四部分:包装起来

    ASP.NET 2.0 System.Web.Security.ActiveDirectoryMembershipProvider

    System.Web.Security.SqlMembershipProvider之间的差别可以作为通过同样一个接口暴露完全不同功能的例子,他们的每个对象都有完全不同的功能,但它们都通过System.Web.Security.Membership对象来暴露同样一个API,这样就有利于编码。

    现在我们大概了解了Provider模式的工作原理了,我们甚至可以写一个自己的MembershipProvider。如果我们想要这个MembershipProviderXML文件获取信息而不是活动目录或是SQL,我们要声明以下类并为基类定义好抽象方法:

    class XmlMembershipProvider: System.Web.Security.MembershipProvider
    {
    }

    讲了这么半天,希望你能了解Provider模式及其工作原理。在很多情况下我们也许可以通过.NET框架现有的API来实现自己的Provider,如果你有兴趣在ASP.NET 2.0中看看自定义的Provider,请参考MSDN

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/ASPNETProvMod_Intro.asp

  • 相关阅读:
    初次使用树莓派并启用root管理员(登录root管理员)
    windows安装laravel框架
    树莓派Raspbian Root密码是多少?
    树莓派学习笔记(1)解决用putty连接时出现connection refused的办法
    linux 根据端口kill掉进程
    swoole入门
    linux环境安装redis及扩展
    linux 命令
    linux 配置域名到指定目录
    微信公众号开发遇到的问题
  • 原文地址:https://www.cnblogs.com/vincedotnet/p/952390.html
Copyright © 2011-2022 走看看