欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
博客園 - 探索設計模式(五):工廠(chǎng)方法模式(Factory Method)

工廠(chǎng)方法模式(Factory Method

——探索設計模式系列之五

Terrylee,200412

概述

在軟件系統中,經(jīng)常面臨著(zhù)“某個(gè)對象”的創(chuàng )建工作,由于需求的變化,這個(gè)對象的具體實(shí)現經(jīng)常面臨著(zhù)劇烈的變化,但是它卻擁有比較穩定的接口。如何應對這種變化?提供一種封裝機制來(lái)隔離出“這個(gè)易變對象”的變化,從而保持系統中“其它依賴(lài)該對象的對象”不隨著(zhù)需求的改變而改變?這就是要說(shuō)的Factory Method模式了。

意圖

定義一個(gè)用戶(hù)創(chuàng )建對象的接口,讓子類(lèi)決定實(shí)例化哪一個(gè)類(lèi)。Factory Method使一個(gè)類(lèi)的實(shí)例化延遲到其子類(lèi)。

結構圖

生活中的例子

工廠(chǎng)方法定義一個(gè)用于創(chuàng )建對象的接口,但是讓子類(lèi)決定實(shí)例化哪個(gè)類(lèi)。壓注成型演示了這種模式。塑料玩具制造商加工塑料粉,將塑料注入到希望形狀的模具中。玩具的類(lèi)別(車(chē),人物等等)是由模具決定的。

工廠(chǎng)方法解說(shuō)

在工廠(chǎng)方法模式中,核心的工廠(chǎng)類(lèi)不再負責所有產(chǎn)品的創(chuàng )建,而是將具體創(chuàng )建工作交給子類(lèi)去做。這個(gè)核心類(lèi)僅僅負責給出具體工廠(chǎng)必須實(shí)現的接口,而不接觸哪一個(gè)產(chǎn)品類(lèi)被實(shí)例化這種細節。這使得工廠(chǎng)方法模式可以允許系統在不修改工廠(chǎng)角色的情況下引進(jìn)新產(chǎn)品。在Factory Method模式中,工廠(chǎng)類(lèi)與產(chǎn)品類(lèi)往往具有平行的等級結構,它們之間一一對應。

現在我們考慮一個(gè)日志記錄的例子(這里我們只是為了說(shuō)明Factory Method模式,實(shí)際項目中的日志記錄不會(huì )這么去做,也要比這復雜一些)。假定我們要設計日志記錄的類(lèi),支持記錄的方法有FileLogEventLog兩種方式。在這里我們先不談設計模式,那么這個(gè)日志記錄的類(lèi)就很好實(shí)現了:

 1
/// <summary>
 2
/// 日志記錄類(lèi)
 3
/// </summary>

 4
public class Log
 5
    
{
 6

 7
        
public void WriteEvent()
 8
        
{
 9
            Console.WriteLine(
"EventLog Success!");
10
        }

11
    
12
        
public void WriteFile()
13
        
{
14
            Console.WriteLine(
"FileLog Success!");
15
        }

16

17
        
public void Write(string LogType)
18
        
{
19
            
switch(LogType.ToLower())
20
            
{
21
                
case "event":
22
                    WriteEvent();
23
                    
break;
24

25
                
case "file":
26
                    WriteFile();
27
                    
break;
28

29
                
default:
30
                    
break;
31
            }

32
        }

33
    }

34

這樣的程序結構顯然不能符合我們的要求,如果我們增加一種新的日志記錄的方式DatabaseLog,那就要修改Log類(lèi),隨著(zhù)記錄方式的變化,switch語(yǔ)句在不斷的變化,這樣就引起了整個(gè)應用程序的不穩定,進(jìn)一步分析上面的代碼,發(fā)現對于EventLogFileLog是兩種完全不同的記錄方式,它們之間不應該存在必然的聯(lián)系,而應該把它們分別作為單獨的對象來(lái)對待。

 1
/// <summary>
 2
/// EventLog類(lèi)
 3
/// </summary>

 4
public class EventLog
 5
{
 6
    
public void Write()
 7
    
{
 8
        Console.WriteLine(
"EventLog Write Success!");
 9
    }

10
}

11

12
/// <summary>
13
/// FileLog類(lèi)
14
/// </summary>

15
public class FileLog
16
{
17
    
public void Write()
18
    
{
19
        Console.WriteLine(
"FileLog Write Success!");
20
    }

21
}

22

進(jìn)一步抽象,為它們抽象出一個(gè)共同的父類(lèi),結構圖如下:

實(shí)現代碼:

1
/// <summary>
2
/// Log類(lèi)
3
/// </summary>

4
public abstract class Log
5
{
6
    
public abstract void Write();
7
}

8

此時(shí)EventLogFileLog類(lèi)的代碼應該如下:

 1
/// <summary>
 2
/// EventLog類(lèi)
 3
/// </summary>

 4
public class EventLog:Log
 5
{
 6
    
public override void Write()
 7
    
{
 8
        Console.WriteLine(
"EventLog Write Success!");
 9
    }

10
}

11
/// <summary>
12
/// FileLog類(lèi)
13
/// </summary>

14
public class FileLog:Log
15
{
16
    
public override void Write()
17
    
{
18
        Console.WriteLine(
"FileLog Write Success!");
19
    }

20
}

21

此時(shí)我們再看增加新的記錄日志方式DatabaseLog的時(shí)候,需要做哪些事情?只需要增加一個(gè)繼承父類(lèi)Log的子類(lèi)來(lái)實(shí)現,而無(wú)需再去修改EventLogFileLog類(lèi),這樣的設計滿(mǎn)足了類(lèi)之間的層次關(guān)系,又很好的符合了面向對象設計中的單一職責原則,每一個(gè)類(lèi)都只負責一件具體的事情。到這里似乎我們的設計很完美了,事實(shí)上我們還沒(méi)有看客戶(hù)程序如何去調用。 在應用程序中,我們要使用某一種日志記錄方式,也許會(huì )用到如下這樣的語(yǔ)句:

EventLog eventlog = new EventLog();
eventlog.Write();

當日志記錄的方式從EventLog變化為FileLog,我們就得修改所有程序代碼中出現上面語(yǔ)句的部分,這樣的工作量是可想而知的。此時(shí)就需要解耦具體的日志記錄方式和應用程序。這就要引入Factory Method模式了,每一個(gè)日志記錄的對象就是工廠(chǎng)所生成的產(chǎn)品,既然有兩種記錄方式,那就需要兩個(gè)不同的工廠(chǎng)去生產(chǎn)了,代碼如下:

 1
/// <summary>
 2
/// EventFactory類(lèi)
 3
/// </summary>

 4
public class EventFactory
 5
{
 6
    
public EventLog Create()
 7
    
{
 8
        
return new EventLog();
 9
    }

10
}

11
/// <summary>
12
/// FileFactory類(lèi)
13
/// </summary>

14
public class FileFactory
15
{
16
    
public FileLog Create()
17
    
{
18
        
return new FileLog();
19
    }

20
}

21

這兩個(gè)工廠(chǎng)和具體的產(chǎn)品之間是平行的結構,并一一對應,并在它們的基礎上抽象出一個(gè)公用的接口,結構圖如下:

實(shí)現代碼如下:

1
/// <summary>
2
/// LogFactory類(lèi)
3
/// </summary>

4
public abstract class LogFactory
5
{
6
    
public abstract Log Create();
7
}

8

此時(shí)兩個(gè)具體工廠(chǎng)的代碼應該如下:

 1
/// <summary>
 2
/// EventFactory類(lèi)
 3
/// </summary>

 4
public class EventFactory:LogFactory
 5
{
 6
    
public override EventLog Create()
 7
    
{
 8
        
return new EventLog();
 9
    }

10
}

11
/// <summary>
12
/// FileFactory類(lèi)
13
/// </summary>

14
public class FileFactory:LogFactory
15
{
16
    
public override FileLog Create()
17
    
{
18
        
return new FileLog();
19
    }

20
}

21

這樣通過(guò)工廠(chǎng)方法模式我們把上面那對象創(chuàng )建工作封裝在了工廠(chǎng)中,此時(shí)我們似乎完成了整個(gè)Factory Method的過(guò)程。這樣達到了我們應用程序和具體日志記錄對象之間解耦的目的了嗎?看一下此時(shí)客戶(hù)端程序代碼:

 1
/// <summary>
 2
/// App類(lèi)
 3
/// </summary>

 4
public class App
 5
{
 6
    
public static void Main(string[] args)
 7
    
{
 8
        LogFactory factory 
= new EventFactory();
 9

10
        Log log 
= factory.Create();
11

12
        log.Write();
13
    }

14
}

15

在客戶(hù)程序中,我們有效地避免了具體產(chǎn)品對象和應用程序之間的耦合,可是我們也看到,增加了具體工廠(chǎng)對象和應用程序之間的耦合。那這樣究竟帶來(lái)什么好處呢?我們知道,在應用程序中,Log對象的創(chuàng )建是頻繁的,在這里我們可以把

LogFactory factory = new EventFactory();

這句話(huà)放在一個(gè)類(lèi)模塊中,任何需要用到Log對象的地方仍然不變。要是換一種日志記錄方式,只要修改一處為:

LogFactory factory = new FileFactory();

其余的任何地方我們都不需要去修改。有人會(huì )說(shuō)那還是修改代碼,其實(shí)在開(kāi)發(fā)中我們很難避免修改,但是我們可以盡量做到只修改一處。

其實(shí)利用.NET的特性,我們可以避免這種不必要的修改。下面我們利用.NET中的反射機制來(lái)進(jìn)一步修改我們的程序,這時(shí)就要用到配置文件了,如果我們想使用哪一種日志記錄方式,則在相應的配置文件中設置如下:

1
<appSettings>
2
    
<add key="factoryName" value="EventFactory"></add>
3
</appSettings>
4

此時(shí)客戶(hù)端代碼如下:

 1
/// <summary>
 2
/// App類(lèi)
 3
/// </summary>

 4
public class App
 5
{
 6
    
public static void Main(string[] args)
 7
    
{
 8
        
string strfactoryName = ConfigurationSettings.AppSettings["factoryName"];
 9
        
10
        LogFactory factory;
11
        factory 
= (LogFactory)Assembly.Load("FactoryMethod").CreateInstance("FactoryMethod." + strfactoryName);
12

13
        Log log 
= factory.Create();
14
        log.Write();
15
    }

16
}

17

現在我們看到,在引進(jìn)新產(chǎn)品(日志記錄方式)的情況下,我們并不需要去修改工廠(chǎng)類(lèi),而只是增加新的產(chǎn)品類(lèi)和新的工廠(chǎng)類(lèi)(注意:這是任何時(shí)候都不能避免的),這樣很好的符合了開(kāi)放封閉原則。

ASP.NET HTTP通道中的應用

Factory Method模式在ASP.NET HTTP通道中我們可以找到很多的例子。ASP.NET HTTP通道是System.Web命名空間下的一個(gè)類(lèi),WEB Server使用該類(lèi)處理接收到的HTTP請求,并給客戶(hù)端發(fā)送響應。HTTP通道主要的工作有Session管理,應用程序池管理,緩存管理,安全等。

System.Web.HttpApplicationFactory

HttpRuntimeHTTP通道的入口點(diǎn),它根據每一個(gè)具體的請求創(chuàng )建一個(gè)HttpContext實(shí)例, HttpRuntime并沒(méi)有確定它將要處理請求的HttpApplication對象的類(lèi)型,它調用了一個(gè)靜態(tài)的工廠(chǎng)方法HttpApplicationFactory.GetApplicationInstance,通過(guò)它來(lái)創(chuàng )建HttpContext實(shí)例。GetApplicationInstance使用HttpContext實(shí)例來(lái)確定針對這個(gè)請求該響應哪個(gè)虛擬路徑,如果這個(gè)虛擬路徑以前請求過(guò),HttpApplication(或者一個(gè)繼承于ASP.Global_asax的類(lèi)的實(shí)例)將直接從應用程序池中返回,否則針對該虛擬路徑將創(chuàng )建一個(gè)新的HttpApplication對象并返回。如下圖所示:

HttpApplicationFactory.GetApplicationInstance帶有一個(gè)類(lèi)型為HttpContext的參數,創(chuàng )建的所有對象(產(chǎn)品)都是HttpApplication的類(lèi)型,通過(guò)反編譯,來(lái)看一下GetApplicationInstance的實(shí)現:

 1
internal static IHttpHandler GetApplicationInstance(HttpContext context)
 2
{
 3
      
if (HttpApplicationFactory._customApplication != null)
 4
      
{
 5
            
return HttpApplicationFactory._customApplication;
 6
      }

 7
      
if (HttpDebugHandler.IsDebuggingRequest(context))
 8
      
{
 9
            
return new HttpDebugHandler();
10
      }

11
      
if (!HttpApplicationFactory._theApplicationFactory._inited)
12
      
{
13
            
lock (HttpApplicationFactory._theApplicationFactory)
14
            
{
15
                  
if (!HttpApplicationFactory._theApplicationFactory._inited)
16
                  
{
17
                        HttpApplicationFactory._theApplicationFactory.Init(context);
18
                        HttpApplicationFactory._theApplicationFactory._inited 
= true;
19
                  }

20
            }

21
      }

22
      
return HttpApplicationFactory._theApplicationFactory.GetNormalApplicationInstance(context);
23
}

24

System.Web.IHttpHandlerFactory

我們來(lái)做進(jìn)一步的探索,HttpApplication實(shí)例需要一個(gè)Handler對象來(lái)處理資源請求, HttpApplication的主要任務(wù)就是找到真正處理請求的類(lèi)。HttpApplication首先確定了一個(gè)創(chuàng )建Handler對象的工廠(chǎng),來(lái)看一下在Machine.config文件中的配置區<httphandlers>,在配置文件注冊了應用程序的具體處理類(lèi)。例如在Machine.config中對*.aspx的處理將映射到System.Web.UI.PageHandlerFactory 類(lèi),而對*.ashx的處理將映射到System.Web.UI.SimpleHandlerFactory 類(lèi),這兩個(gè)類(lèi)都是繼承于IhttpHandlerFactory接口的具體類(lèi)

<httpHandlers>

<add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory" />

<add verb="*" path="*.ashx" type="System.Web.UI.SimpleHandlerFactory" />



</httpHandlers>

這個(gè)配置區建立了資源請求的類(lèi)型和處理請求的類(lèi)之間的一個(gè)映射集。如果一個(gè).aspx頁(yè)面發(fā)出了請求,將會(huì )調用System.Web.UI.PageHandlerFactory類(lèi),HttpApplication調用接口IHttpHandlerFactory中的工廠(chǎng)方法GetHandler來(lái)創(chuàng )建一個(gè)Handler對象。當一個(gè)名為sample.aspx的頁(yè)面發(fā)出請求時(shí),通過(guò)PageHandlerFactory將返回一個(gè)ASP.SamplePage_aspx對象(具體產(chǎn)品),如下圖:

IHttpHandlerFactory工廠(chǎng):

1
public interface IHttpHandlerFactory
2
{
3
      
// Methods
4
      IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated);
5
      
void ReleaseHandler(IHttpHandler handler);
6
}

7

IHttpHandlerFactory.GetHandler是一個(gè)工廠(chǎng)方法模式的典型例子,在這個(gè)應用中,各個(gè)角色的設置如下:

抽象工廠(chǎng)角色:IHttpHandlerFactory

具體工廠(chǎng)角色:PageHandlerFactory

抽象產(chǎn)品角色:IHttpHandler

具體產(chǎn)品角色:ASP.SamplePage_aspx

進(jìn)一步去理解

理解上面所說(shuō)的之后,我們就可以去自定義工廠(chǎng)類(lèi)來(lái)對特定的資源類(lèi)型進(jìn)行處理。第一步我們需要創(chuàng )建兩個(gè)類(lèi)去分別實(shí)現IHttpHandlerFactory IHttpHandler這兩個(gè)接口。

 1
public class HttpHandlerFactoryImpl:IHttpHandlerFactory {
 2
   
 3
   IHttpHandler IHttpHandlerFactory.GetHandler(
 4
      HttpContext context, String requestType, 
 5
      String url, String pathTranslated ) 
{
 6

 7
         
return new HttpHandlerImpl();
 8
         
 9
   }
//IHttpHandlerFactory.GetHandler
10

11
   
void IHttpHandlerFactory.ReleaseHandler(
12
      IHttpHandler handler) 
/*no-op*/ }
13

14
}
//HttpHandlerFactoryImpl
15

16
public class HttpHandlerImpl:IHttpHandler {
17

18
   
void IHttpHandler.ProcessRequest(HttpContext context) {
19
      
20
      context.Response.Write(
"sample handler invoked
");
21
      
22
   }
//ProcessRequest
23

24
   
bool IHttpHandler.IsReusable get return false; } }
25

26
}
//HttpHandlerImpl
27

第二步需要在配置文件中建立資源請求類(lèi)型和處理程序之間的映射。我們希望當請求的類(lèi)型為*.sample時(shí)進(jìn)入我們自定義的處理程序,如下:

<httpHandlers>

   
<add verb="*" path="*.sample" 

      type
="HttpHandlerFactoryImpl,SampleHandler" />

</httpHandlers>

最后一步我們需要把文件擴展*.sample映射到ASP.NET ISAPI擴展DLLaspnet_isapi.dll)上。由于我們已經(jīng)建立了用于處理新擴展文件的處理程序了,我們還需要把這個(gè)擴展名告訴IIS并把它映射到ASP.NET。如果你不執行這個(gè)步驟而試圖訪(fǎng)問(wèn)*.sample文件,IIS將簡(jiǎn)單地返回該文件而不是把它傳遞給ASP.NET運行時(shí)。其結果是該HTTP處理程序不會(huì )被調用。

運行Internet服務(wù)管理器,右鍵點(diǎn)擊默認Web站點(diǎn),選擇屬性,移動(dòng)到主目錄選項頁(yè),并點(diǎn)擊配置按鈕。應用程序配置對話(huà)框彈出來(lái)了。點(diǎn)擊添加按鈕并在可執行字段輸入aspnet_isapi.dll文件路徑,在擴展字段輸入.sample。其它字段不用處理;該對話(huà)框如下所示:

.NET Framework中,關(guān)于工廠(chǎng)模式的使用有很多的例子,例如IEnumerableIEnumerator就是一個(gè)Creator和一個(gè)Product;System.Security.Cryptography中關(guān)于加密算法的選擇,SymmetricAlgorithm, AsymmetricAlgorithm, HashAlgorithm分別是三個(gè)工廠(chǎng),他們各有一個(gè)靜態(tài)的工廠(chǎng)方法Create;System.Net.WebRequest .NET Framework 的用于訪(fǎng)問(wèn) Internet 數據的請求/響應模型的抽象基類(lèi)。使用該請求/響應模型的應用程序可以用協(xié)議不可知的方式從 Internet 請求數據。在這種方式下,應用程序處理 WebRequest 類(lèi)的實(shí)例,而協(xié)議特定的子類(lèi)則執行請求的具體細節。請求從應用程序發(fā)送到某個(gè)特定的 URI,如服務(wù)器上的 Web 頁(yè)。URI 從一個(gè)為應用程序注冊的 WebRequest 子代列表中確定要創(chuàng )建的適當子類(lèi)。注冊 WebRequest 子代通常是為了處理某個(gè)特定的協(xié)議(如 HTTP FTP),但是也可以注冊它以處理對特定服務(wù)器或服務(wù)器上的路徑的請求。有時(shí)間我會(huì )就.NET Framework中工廠(chǎng)模式的使用作一個(gè)專(zhuān)題總結。

實(shí)現要點(diǎn)

1.  Factory Method模式的兩種情況:一是Creator類(lèi)是一個(gè)抽象類(lèi)且它不提供它所聲明的工廠(chǎng)方法的實(shí)現;二是Creator是一個(gè)具體的類(lèi)且它提供一個(gè)工廠(chǎng)方法的缺省實(shí)現。

2.  工廠(chǎng)方法是可以帶參數的。

3.  工廠(chǎng)的作用并不僅僅只是創(chuàng )建一個(gè)對象,它還可以做對象的初始化,參數的設置等。

效果

1.  用工廠(chǎng)方法在一個(gè)類(lèi)的內部創(chuàng )建對象通常比直接創(chuàng )建對象更靈活。

2.  Factory Method模式通過(guò)面向對象的手法,將所要創(chuàng )建的具體對象的創(chuàng )建工作延遲到了子類(lèi),從而提供了一種擴展的策略,較好的解決了這種緊耦合的關(guān)系。

適用性

在以下情況下,適用于工廠(chǎng)方法模式:

1.       當一個(gè)類(lèi)不知道它所必須創(chuàng )建的對象的類(lèi)的時(shí)候。

2.       當一個(gè)類(lèi)希望由它的子類(lèi)來(lái)指定它所創(chuàng )建的對象的時(shí)候。

3.       當類(lèi)將創(chuàng )建對象的職責委托給多個(gè)幫助子類(lèi)中的某一個(gè),并且你希望將哪一個(gè)幫助子類(lèi)是代理者這一信息局部化的時(shí)候。

總結

Factory Method模式是設計模式中應用最為廣泛的模式,通過(guò)本文,相信讀者已經(jīng)對它有了一定的認識。然而我們要明確的是:在面向對象的編程中,對象的創(chuàng )建工作非常簡(jiǎn)單,對象的創(chuàng )建時(shí)機卻很重要。Factory Method要解決的就是對象的創(chuàng )建時(shí)機問(wèn)題,它提供了一種擴展的策略,很好地符合了開(kāi)放封閉原則。__________________________________________________________________________________

參考文獻:

《設計模式》(中文版)

MSDN:《Exploring the Factory Design Pattern

DesignPatternsExplained

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
GoF設計模式之三 Factory Method- -
設計模式分類(lèi)
7. 工廠(chǎng)系列
J<span style="font-weight: normal;">ava 23種設計模式</span>
工廠(chǎng)方法模式(Factory Method Pattern)
小菜學(xué)習設計模式(三)—工廠(chǎng)方法(Factory Method)模式
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久