❶ C# 資料庫連接關於工廠方法
你下個動軟的C#資料庫代碼自動生成器,用他生成一個資料庫項目,而且是工廠模式的,自己看一下就明白了,基本上介面只能得到每個欄位的值或者設置欄位的值,而工廠內部實現了不同資料庫的調用方法。最後具體使用哪個工廠,則來自於config配置文件中的工廠命名,通過反射可以實例化工廠,並且實現介面。那個例子是非常經典的,自己看下吧
❷ 反射+抽象工廠是資料庫訪問的最佳實踐嗎
反射+工程模式 是jdbc常用的一種連接資料庫的編碼方式,這樣做主要是未來避免Jdbc的硬編碼,也就是說避免將連接資料庫的信息寫死在程序里。如果寫死了那麼不便於移植和維護,比如資料庫的url換了,那麼你要改程序,並且重新編譯。如果用戶名密碼換了也要改。如果直接連資料庫也換了,那又要重新改代碼,編譯。這樣維護的成本會大大提高。如果將這些信息寫在配置文件里,那麼有相關改動是不需要改程序,直接改配置文件並重啟服務就可以。反射+抽象工廠是資料庫訪問的好處。想hibernate這些開源框架,也是把資料庫的連接信息寫在配置文件中的,主要是為了發生變動是好維護!
❸ 抽象工廠設計模式
抽象工廠:主要功能是生產抽象產品; 如:生產學員、管理員等抽象產品。 抽象產品:主要功能是提供實體產品訪問介面; 如:提供學員、管理員等實體產品數據訪問的介面。 實體工廠:主要功能是生產實體產品; 如:sql Server和Access形式的學員、管理員等數據訪問對象。 實體產品:主要功能是實現自己的功能; 如:分別實現不同的資料庫訪問。 詳見: http://www.cnblogs.com/xugang/archive/2008/06/11/1217227.html
❹ 在抽象工廠模式中怎樣使用memcached緩存數據
一、Memcached簡介
memcached 常被用來加速應用程序的處理,在這里,我們將著重於介紹將它部署於應用程序和環境中的最佳實踐。這包括應該存儲或不應存儲哪些、如何處理數據的靈活分布以 及如何調節用來更新 memcached 和所存儲數據的方法。我們還將介紹對高可用性的解決方案的支持,比如 IBM WebSphere® eXtreme Scale。
所有的應用程序,特別是很多 web 應用程序都需要優化它們訪問客戶機和將信息返回至客戶機的速度。可是,通常,返回的都是相同的信息。從數據源(資料庫或文件系統)載入數據十分低效,若是每次想要訪問該信息時都運行相同的查詢,就尤顯低效。
雖然很多 web 伺服器都可被配置成使用緩存發回信息,但那與大多數應用程序的動態特性無法相適。而這正是 memcached 的用武之地。它提供了一個通用的內存存儲器,可保存任何東西,包括本地語言的對象,這就讓您可以存儲各種各樣的信息並可以從諸多的應用程序和環境訪問這些信息。
二、基礎知識
memcached 是一個開源項目,旨在利用多個伺服器內的多餘 RAM 來充當一個可存放經常被訪問信息的內存緩存。這里的關鍵是使用了術語緩存:memcached 為載入自他處的信息提供的是內存中的暫時存儲。
比如,考慮這樣一個典型的基於 web 的應用程序。即便是一個動態網站可能也會有一些組件或信息常量是貫穿頁面整個生命周期的。在一個博客站點內,針對單個 blog post 的類別列表不大可能在頁面查看間經常性地變更。每次都通過一個對資料庫的查詢載入此信息相對比較昂貴,特別是在數據沒有更改的情況下,就更是如此。從圖 1 可以看到一個博客站點內可被緩存的頁面分區。
圖1.一個典型的博客頁面內的可緩存元素
將這種結構放在 blog 站點的其他元素,poster 信息、注釋 — 設置 blog post 本身 — 進行推斷,可以看出為了顯示主頁的內容很可能需要發生 10-20 次資料庫查詢和格式化。 每天對數百甚至數千的的頁面查看重復此過程,那麼您的伺服器和應用程序執行的查詢要遠遠多於為了顯示頁面內容所需執行的查詢。
通過使用 memcached,可以將載入自資料庫的格式化信息存儲為一種可直接用在 Web 頁面上的格式。並且由於信息是從 RAM 而不是通過資料庫和其他處理從磁碟載入的,所以對信息的訪問幾乎是瞬時的。
再強調一下,memcached 是一個用來存儲常用信息的緩存,有了它,您便無需從緩慢的資源,比如磁碟或資料庫,載入並處理信息了。
對 memcached 的介面是通過網路連接提供的。這意味著您可以在多個客戶機間共享單個的 memcached 伺服器(或多個伺服器,如本文稍後所示的)。這個網路介面非常迅速,並且為了改善性能,伺服器會故意不支持身份驗證或安全性通信。但這不應限制部署選項。 memcached 伺服器應該存在於您網路的內部。網路介面的實用性以及可以部署多個 memcached 實例的簡便性讓您可以使用多個機器上的多餘 RAM 來提高您緩存的整體大小。
三、存儲方法
memcached 的存儲方法是一個簡單的鍵/值對,類似於很多語言內的散列或關聯數組。通過提供鍵和值來將信息存儲到 memcached 內,通過按特定的鍵請求信息來恢復信息。
信息會無限期地保留在緩存內,除非發生如下的情況:
為緩存分配的內存耗盡 — 在這種情況下,memcached 使用 LRU(最近最少使用)方法從此緩存刪除條目。最近未曾使用的條目會從此緩存中先刪除,最舊的最先訪問。
條目被明確刪除 — 總是可以從此緩存內刪除條目。
條目過期失效 — 各條目均有一個有效的期限以便針對此鍵存儲的信息在過於陳舊時可從緩存中清除這些條目。
上述這些情況可以與您應用程序的邏輯綜合使用以便確保緩存內的信息是最新的。有了這些基礎知識後,讓我們來看看在應用程序內如何能最好地利用 memcached。
四、何時使用memcached?
在使用 memcached 改進應用程序性能時,可以對一些關鍵的過程和步驟進行修改。
在載入信息時,典型的場景如圖 2 所示。
圖2.載入要顯示的信息的典型順序
一般而言,這些步驟是:
執行一個或多個查詢來從資料庫載入信息
格式化適合於顯示(或進一步處理)的信息
使用或顯示格式化了的數據
在使用 memcached 時,為配合這個緩存,可對應用程序的邏輯進行稍許修改:
盡量從緩存載入信息
如果存在,使用信息的被緩存版本
如果它不存在:
執行一個或多個查詢來從資料庫載入信息
格式化適合於顯示或進一步處理的信息
將信息存儲到緩存內
使用格式化了的數據
圖 3 是對這些步驟的總結。
圖3.在使用memcached時載入適合於顯示的信息
數據載入成為了至多三個步驟的一個過程,從緩存載入數據或從資料庫(視情況而定)載入數據並存儲在緩存內。
當這個過程首次發生時,數據將正常地從資料庫或其他數據源載入,然後再存儲到 memcached 內。當下一次訪問此信息時,它就會從 memcached 拉出,而不是從資料庫載入,節省了時間和 CPU 循環。
問題的另一個方面是要確保如果更改了要存儲在 memcached 內的信息,在更新後端信息的同時還要更新 memcached 的版本。這會讓圖 4 內所示的這個典型順序發生稍許變化,如 圖 5 所示。
圖4.在一個典型的應用程序內更新或存儲數據
圖 5 顯示了使用 memcached 後發生了變化的流程。
圖5.在使用memcached時更新或存儲數據
比如,仍以博客站點為例,在博客系統更新資料庫內的類別列表時,更新應該遵循如下順序:
更新資料庫內的類別列表
格式化信息
將信息存儲到 memcached 內
將信息返回至客戶機
memcached 內的存儲操作是原子的,所以信息的更新不會讓客戶機只獲得部分數據;它們獲得的或者是老版本,或者是新版本。
對於大多數應用程序,這兩個操作是您惟一需要注意的。在訪問他人使用的數據時,它會自動被添加到這個緩存內,而且如果對該數據進行了更改,此緩存內也會自動進行更新。
五、鍵、名稱空間和值
memcached 另一個需要重點考慮的因素是如何組織和命名存儲在緩存內的這些數據。從之前博客站點的例子中,不難看出需要使用一種一致的命名結構以便您能載入博客類別、歷史和其他信息,然後再在載入信息(並更新緩存)時或者在更新數據(同樣也要更新緩存)時使用。
使用的何種具體的命名系統特定於應用程序,但通常可以使用一種與現有應用程序類似的結構,並且這種結構很可能基於某種惟一識別符。當從資料庫拉出信息或在整理信息集時,就會發生這種情況。
以 blog post 為例,可以在一個具有鍵 category-list 的項中存儲類別列表。與此 post ID 對應的單個 post,比如 blogpost-29 相關的值都可以使用,而該項的注釋則可以存儲在 blogcomments-29內,其中 29 就是這個 blog post 的 ID。這樣一來, 您就可以將各種各樣的信息存儲在緩存內,使用不同的前綴來標識這些信息。
memcached 鍵/值存儲的簡便性(以及安全性的缺乏)意味著如果您想要在使用同一個 memcached 伺服器的同時支持多個應用程序,那麼就可以考慮使用其他格式的量詞來標識數據屬於某種特定的應用程序。比如,可以添加像 blogapp:blogpost-29 這樣的應用程序前綴。這些鍵是沒有格式的,所以可以使用任何字元串作為鍵的名稱。
在存儲值的方面,應該確保存儲在緩存內的信息適合於您的應用程序。比如,對於這個博客系統,您可能想要存儲被博客應用程序使用的對象以便格式化博客信息,而不是原始的 HTML。如果同一個基礎結構用在應用程序內的多個地方,這一點更具實用性。
大多數語言的介面,包括 Java™、Perl、PHP 等,都能串列化語言對象以便存儲在 memcached 內。這就讓您可以存儲並隨後從內存存儲恢復全部對象,而不是在您的應用程序內手動重構它們。 很多對象,或它們使用的結構,都基於某種散列或數組結構。對於跨語言的環境,比如在 JSP 環境和 JavaScript 環境間共享相同信息,可以使用一種架構中立的格式,比如 JavaScript Object Notation (JSON) 甚或 XML。
六、填充並使用memcached
作為一種開源產品以及一種最初開發用來工作於現有開源環境內的產品,memcached 受大量環境和平台支持。與 memcached 伺服器通信的介面有很多,並常常具有針對所有語言的多個實現。參見參考資料 以獲得常用的庫和工具箱。
要列出所有受支持的介面和環境不太可能,但它們均支持 memcached 協議提供的基礎 API。這些描述已經被簡化並應用在不同語言的上下文內,在這些語言中,使用不同的值可指示錯誤。主要的函數有:
get(key) — 從存儲了特定鍵的 memcached 獲得信息。 如果鍵不存在,就返回錯誤。
set(key, value [, expiry]) — 使用緩存內的標識符鍵存儲這個特定的值。如果鍵已經存在,那麼它就會被更新。期滿時間的單位為秒,並且如果值小於 30 天 (30*24*60*60),那麼就用作相對時間,如果值大於 30 天,那麼就用作絕對時間 (epoch)。
add(key, value [, expiry]) — 如果鍵不存在就將這個鍵添加到緩存內,如果鍵已經存在就返回錯誤。如果您想要顯式地添加一個新鍵而又不會因它已經存在而更新它,那麼這個函數將十分有用。
replace(key, value [, expiry]) — 更新此特定鍵的值,如果鍵不存在就返回一個錯誤。
delete(key [, time]) — 從緩存中刪除此鍵/值對。如果您提供一個時間,那麼添加具有此鍵的一個新值就會被阻塞這個特定的時期。超時讓您可以確保此值總是可以重新讀取自您的數據中心。
incr(key [, value]) — 為特定的鍵增 1 或特定的值。只適用於數值。
decr(key [, value]) — 為特定的鍵減 1 或特定的值,只適用於數值。
flush_all — 讓緩存內的所有當前條目無效(或到期失效)。
比如,在 Perl 內,基本 set 操作可以如清單 1 所示的那樣處理。
清單 1. Perl 內的基本 set 操作
use Cache::Memcached;
my $cache = new Cache::Memcached {
'servers' => [
'localhost:11211',
],
};
$cache->set('mykey', 'myvalue');
Ruby 內的相同的基本操作如清單 2 所示。
清單 2. Ruby 內的基本 set 操作
require 'memcache'
memc = MemCache::new '192.168.0.100:11211'
memc["mykey"] = "myvalue"
在兩個例子中可以看到相同的基本結構:設置 memcached 伺服器,然後分配或設置值。其他的介面也可用,包括適合於 Java 技術的那些介面,讓您可以在 WebSphere 應用程序內使用 memcached。memcached 介面類允許將 Java 對象直接序列化到 memcached 以便於存儲和載入復雜的結構。當在像 WebSphere 這樣的環境內進行部署時,有兩個事情非常重要:服務的彈性(在 memcached 不可用時如何做)以及如何提高緩存存儲量來改進在使用多個應用程序伺服器或在使用像 WebSphere eXtreme Scale 這樣的環境時的性能。我們接下來就來看看這兩個問題。
七、彈性和可用性
有關 memcached 最常見的一個問題是:「若緩存不可用了,會發生什麼情況呢?」正如之前章節中明示的,緩存內的信息不應該成為信息的的惟一資源。必須要能夠從其他位置載入存儲在緩存內的數據。
雖然,無法從緩存訪問信息將會減緩應用程序的性能,但它不應該阻止應用程序的運轉。可能會發生這樣幾個場景:
如果 memcached 服務宕掉,應用程序應該回退到從原始數據源載入信息並對信息進行顯示所需的格式化。此應用程序還應繼續嘗試在 memcached 內載入和存儲信息。
一旦 memcached 伺服器恢復可用,應用程序就應該自動嘗試存儲數據。沒有必要強制重載已緩存了的數據,可以使用標準的訪問來用信息載入和填充緩存。最終,緩存將會被最常用的數據重新填充。
再次重申,memcached 是信息的緩存但並非惟一的數據源。memcached 伺服器不可用不應該是應用程序的終結,雖然這意味著在 memcached 伺服器恢復正常之前性能會有所降低。實際上,memcached 伺服器相對簡單,並且雖然不是絕對無故障的,但它的簡單性的結果就是它很少會出錯。
八、分配緩存
memcached 伺服器只是網路上針對一些鍵存儲值的一個緩存。如果有多台機器,那麼很自然地會想要在所有多餘機器上設置一個 memcached 的實例來提供一個超大的聯網 RAM 緩存存儲。
有了這個想法後,還有一種想當然是需要使用某種分配或復制機制來在機器之間復制鍵/值對。這種方式的問題是如果這么做反而會減少可用的 RAM 緩存,而不是增加。如圖 6 所示,可以看出這里有三個應用程序伺服器,每個伺服器都可以訪問一個 memcached 實例。
圖6.多重memcached實例的不正確使用
盡管每個 memcached 實例都是 1 GB 的大小(產生 3 GB 的 RAM 緩存),但如果每個應用程序伺服器只有其自己的緩存(或者在 memcached 之間存在著數據的復制),那麼整個安裝也仍只能有 1 GB 的緩存在每個實例間復制。
由於 memcached 通過一個網路介面提供信息,因此單個的客戶機可以從它所能訪問的任何一個 memcached 實例訪問數據。如果數據沒有跨每個實例被復制,那麼最終在每個應用程序伺服器上,就可以有 3 GB 的 RAM 緩存可用,如圖 7 所示。
圖7.多重memcached實例的正確使用
這個方法的問題是選擇哪個伺服器來儲存鍵/值對,以及當想要重新獲得一個值時,如何決定要與哪個 memcached 伺服器對話。問題的解決方案就是忽略復雜的東西,比如查找表,或是寄望 memcached 伺服器來為您處理這個過程。而 memcached 客戶機則必須要力求簡單。
memcached 客戶機不必決定此信息,它只需對在存儲信息時指定的鍵使用一個簡單的散列演算法。當想要從一列 memcached 伺服器存儲或獲取信息時,memcached 客戶機就會用一個一致的散列演算法從這個鍵獲取一個數值。舉個例子,鍵 mykey 被轉換成數值 23875 。是保存還是獲取信息無關緊要,這個鍵將總是被用作惟一標識符來從 memcached 伺服器載入,因此在本例中,「mykey」 散列轉化後對應的值總是 23875。
如果有兩個伺服器,那麼 memcached 客戶機將對這個數值進行一個簡單的運算(例如,系數)來決定它應將此值存儲在第一個還是第二個配置了的 memcached 實例上。
當存儲一個值時,客戶機會從這個鍵確定出散列值以及它原來存儲在哪個伺服器上。當獲取一個值時,客戶機會從這個鍵確定出相同的散列值並會選擇相同的伺服器來獲取信息。
如果在每個應用程序伺服器上使用的是相同的伺服器列表(並且順序相同),那麼當需要保存或檢索同一個鍵時,每個應用程序伺服器都將選擇同一個 伺服器。現在,在這個例子中,有 3GB 的 memcached 空間可以共享,而不是同一個 1 GB 的空間的復制,這就帶來了更多的可用緩存,並很有可能會提高有多個用戶情況下的應用程序的性能。
九、如何能不使用memcached?
盡管 memcached 很簡單,但 memcached 實例有時候還是會被不正確地使用。
memcached不是一個資料庫
最常見的 memcached 誤用就是把它用作一個數據存儲,而不是一個緩存。memcached 的首要目的就是加快數據的響應時間,否則數據從其他數據源構建或恢復需要很長時間。一個典型的例子就是從一個資料庫中恢復信息,特別是在信息顯示給用戶前 需要對信息進行格式化或處理的時候。Memcached 被設計用來將信息存儲在內存中以避免每次在數據需要恢復時重復執行相同的任務。
切不可將 memcached 用作運行應用程序所需信息的惟一信息源;數據應總是可以從其他信息源獲取。此外,要記住 memcached 只是一個鍵/值的存儲。不能在數據上執行查詢,或者對內容進行迭代來提取信息。應該使用它來存儲數據塊或對象以備批量使用。
不要緩存資料庫行或文件
雖然可以使用 memcached 存儲載入自資料庫的數據行,但這實際上是查詢緩存,並且大多數資料庫都提供各自的查詢緩存的機制。其他的對象,比如文件系統的圖像或文件的情況與此相同。很多應用程序和 web 伺服器針對此類工作已經有了一些很好的解決方案。
如果在載入和格式化後,使用它來存儲全部信息塊,就可以從 memcached 獲得更多的實用工具和性能上的改善。仍以我們的博客站點為例,存儲信息的最佳點是在將博客類別格式化為對象,甚至是在格式化成 HTML 後。博客頁面的構造可通過從 memcached 載入各個組件(比如 blog post、category list、post history 等)並將完成的 HTML 寫回至客戶機實現。
memcached並不安全
為了確保最佳性能,memcached 並未提供任何形式的安全性,沒有身份驗證,也沒有加密。這意味著對 memcached 伺服器的訪問應該這么處理:一是通過將它們放到應用程序部署環境相同的私有側,二是如果安全性是必須的,那麼就使用 UNIX® socket 並只允許當前主機上的應用程序訪問此 memcached 伺服器。
這多少犧牲了一些靈活性和彈性,以及跨網路上的多台機器共享 RAM 緩存的能力,但這是在目前的情況下確保 memcached 數據安全性的惟一一種解決方案。
十、不要限制自己
除了不應該使用 memcached 實例的情況外,memcached 的靈活性不應忽視。由於 memcached 與應用程序處於相同的架構水平,所以很容易集成並連接到它。並且更改應用程序以便利用 memcached 也並不復雜。此外,由於 memcached 只是一個緩存,所以在出現問題時它不會停止應用程序的執行。如果使用正確的話,它所做的是減輕其餘伺服器基礎設施的負載(減少對資料庫和數據源的讀操 作),這意味著無需更多的硬體就可以支持更多的客戶機。
但請記住,它僅僅是個緩存!
結束語
在本文中,我們了解了 memcached 以及如何最佳地使用它。我們看到了信息如何存儲、如何選擇合理的鍵以及如何選擇要存儲的信息。我們還討論了所有 memcached 用戶都要遇到的一些關鍵的部署問題,包括多伺服器的使用、當 memcached 實例消亡時該怎麼做,以及(也許最為重要的)在哪些情況下不能使用 memcached。
作為一種開源的應用程序並且是目的簡單而直白的應用程序,memcached 的功能和實用性均來自於這種簡單性。通過為信息提供巨大的 RAM 存儲空間、讓它在網路上可用,然後再讓它可通過各種不同的介面和語言訪問到,memcached 可被集成到多種多樣的安裝和環境中。
❺ C#抽象工廠有什麼好處
抽象工廠中的結構圖:
抽象工廠:生產抽象產品;
抽象產品:提供實體產品訪問結果;
實體工廠 :生產實體產品;
實體產品:實現功能;
抽象工廠設計模式的概念是:
1提供一系列相互依賴對象的創建;
2.封裝對象的常規方法(new);
3,提供統一調用數據訪問方法的方式;
4.避免調用數據訪問方法和具體創建工作的緊耦合;
❻ 抽象工廠模式,資料庫連接問題,要java源代碼
djftryrtydgswertrtert
❼ .Net中抽象工廠的作用,只是能更換資料庫嗎
看你的思維方式和你考慮問題的出發點
普通三層是所以東西已知,架構是豎井方式
抽象工廠則是面向未知,架構是橫向擴展。
不知道你是否有過ui上的一點變化,你都要從上往下改Bil,Dal層的代碼的經歷
如果有那你就知道抽象工廠是干嗎用的了,3層以上是5層,7層為啥多了一些層,這些層都干嗎的。呵呵,實際上多出來的部分基本都是介面層和介面的抽象工廠層
要知道現代的軟體設計並不是說光完成實現而已,多數是為了方便自己更改,維護和擴展,如果只是光實現的話,一層足已
❽ 工廠模式的抽象工廠
工廠模式中有: 工廠方法(Factory Method) 抽象工廠(Abstract Factory).
這兩個模式區別在於需要創建對象的復雜程度上。如果我們創建對象的方法變得復雜了,如上面工廠方法中是創建一個對象Sample,如果我們還有新的產品介面Sample2.
這里假設:Sample有兩個實體類SampleA和SampleB,而Sample2也有兩個實體類Sample2A和Sample2B
那麼,我們就將上例中Factory變成抽象類,將共同部分封裝在抽象類中,不同部分使用子類實現,下面就是將上例中的Factory拓展成抽象工廠: publicabstractclassFactory{publicabstractSamplecreator();publicabstractSample2creator(Stringname);}{publicSamplecreator(){.........returnnewSampleA}publicSample2creator(Stringname){.........returnnewSample2A}}{publicSamplecreator(){......returnnewSampleB}publicSample2creator(Stringname){......returnnewSample2B}}從上面看到兩個工廠各自生產出一套Sample和Sample2,也許你會疑問,為什麼我不可以使用兩個工廠方法來分別生產Sample和Sample2?
抽象工廠還有另外一個關鍵要點,是因為 SimpleFactory內,生產Sample和生產Sample2的方法之間有一定聯系,所以才要將這兩個方法捆綁在一個類中,這個工廠類有其本身特徵,也許製造過程是統一的,比如:製造工藝比較簡單,所以名稱叫SimpleFactory。
在實際應用中,工廠方法用得比較多一些,而且是和動態類裝入器組合在一起應用,
舉例
我們以Jive的ForumFactory為例,這個例子在前面的Singleton模式中我們討論過,再討論其工廠模式: {privatestaticObjectinitLock=newObject();privatestaticStringclassName="com.jivesoftware.forum.database.DbForumFactory";=null;(Authorizationauthorization){//,returnnull.if(authorization==null){returnnull;}//以下使用了Singleton單態模式if(factory==null){synchronized(initLock){if(factory==null){......try{//動態轉載類Classc=Class.forName(className);factory=(ForumFactory)c.newInstance();}catch(Exceptione){returnnull;}}}}//Now,返回proxy.用來限制授權對forum的訪問returnnewForumFactoryProxy(authorization,factory,factory.getPermissions(authorization));}//真正創建forum的方法由繼承forumfactory的子類去完成.(Stringname,Stringdescription)throwsUnauthorizedException,ForumAlreadyExistsException;....}因為Jive是通過資料庫系統存放論壇帖子等內容數據,如果希望更改為通過文件系統實現,這個工廠方法ForumFactory就提供了提供動態介面:
private static String className = "com.jivesoftware.forum.database.DbForumFactory";
你可以使用自己開發的創建forum的方法代替com.jivesoftware.forum.database.DbForumFactory就可以.
在上面的一段代碼中一共用了三種模式,除了工廠模式外,還有Singleton單態模式,以及proxy模式,proxy模式主要用來授權用戶對forum的訪問,因為訪問forum有兩種人:一個是注冊用戶 一個是遊客guest,那麼那麼相應的許可權就不一樣,而且這個許可權是貫穿整個系統的,因此建立一個proxy,類似網關的概念,可以很好的達到這個效果.
看看Java寵物店中的CatalogDAOFactory: publicclassCatalogDAOFactory{/***本方法制定一個特別的子類來實現DAO模式。*具體子類定義是在J2EE的部署描述器中。*/publicstaticCatalogDAOgetDAO()throwsCatalogDAOSysException{CatalogDAOcatDao=null;try{InitialContextic=newInitialContext();//動態裝入CATALOG_DAO_CLASS//可以定義自己的CATALOG_DAO_CLASS,從而在無需變更太多代碼//的前提下,完成系統的巨大變更。StringclassName=(String)ic.lookup(JNDINames.CATALOG_DAO_CLASS);catDao=(CatalogDAO)Class.forName(className).newInstance();}catch(NamingExceptionne){("CatalogDAOFactory.getDAO::
"+ne.getMessage());}catch(Exceptionse){("CatalogDAOFactory.getDAO:ExceptionwhilegettingDAOtype:
"+se.getMessage());}returncatDao;}}CatalogDAOFactory是典型的工廠方法,catDao是通過動態類裝入器className獲得CatalogDAOFactory具體實現子類,這個實現子類在Java寵物店是用來操作catalog資料庫,用戶可以根據資料庫的類型不同,定製自己的具體實現子類,將自己的子類名給與CATALOG_DAO_CLASS變數就可以。
由此可見,工廠方法確實為系統結構提供了非常靈活強大的動態擴展機制,只要我們更換一下具體的工廠方法,系統其他地方無需一點變換,就有可能將系統功能進行改頭換面的變化。
設計模式如何在具體項目中應用見《Java實用系統開發指南》
❾ java 抽象工廠模式
工廠模式在項目中是常常用到的,有人說只有大項目才會用到,小項目是體會不出來.其實使用設計模式與項目的大小沒有實質性的聯系.設計模式是經驗的總結而不是衡量項目大小的標准.
以開發項目的DAO層為例,在項目中客戶的需求是常常變動的,臨時更換資料庫的需求也是常常發生的,那我們要如何解決跨資料庫的功能,這里就要使用到抽象工廠模式了.工廠模式常常用於創建多系列化的對象(如Orale系列,MySql系列)
1.首先定義相關介面(與平常的做法沒什麼區別)
Java代碼
// 角色表DAO介面
interface IroleDao {
void insert();
void update();
}
// 用戶表DAO介面
interface IuserDao {
void find();
void delete();
}
// 角色表DAO介面
interface IroleDao {
void insert();
void update();
}
// 用戶表DAO介面
interface IuserDao {
void find();
void delete();
} 2.不同的資料庫有不同的SQL語句所以實現時必須分資料庫來實現
Java代碼
// 用戶表Oralce資料庫DAO
class OracleuserDao implements IuserDao {
public void delete() {
System.out.println("Oralce 刪除用戶表數據");
}
public void find() {
System.out.println("Oralce 查詢用戶表數據");
}
}
// 用戶表MySql資料庫DAO
class MySqluserDao implements IuserDao {
public void delete() {
System.out.println("MySql 刪除用戶數據");
}
public void find() {
System.out.println("MySql 查詢用戶數據");
}
}
// 角色表Oracle資料庫DAO
class OracleroleDao implements IroleDao {
public void insert() {
System.out.println("Oralce 對角色表插入數據");
}
public void update() {
System.out.println("Oracle 對角色表更新數據");
}
}
// 角色表MySql資料庫DAO
class MySqlroleDAO implements IroleDao {
public void insert() {
System.out.println("MySql 對角色表插入數據");
}
public void update() {
System.out.println("Mysql 對角色表更新數據");
}
}
// 用戶表Oralce資料庫DAO
class OracleuserDao implements IuserDao {
public void delete() {
System.out.println("Oralce 刪除用戶表數據");
}
public void find() {
System.out.println("Oralce 查詢用戶表數據");
}
}
// 用戶表MySql資料庫DAO
class MySqluserDao implements IuserDao {
public void delete() {
System.out.println("MySql 刪除用戶數據");
}
public void find() {
System.out.println("MySql 查詢用戶數據");
}
}
// 角色表Oracle資料庫DAO
class OracleroleDao implements IroleDao {
public void insert() {
System.out.println("Oralce 對角色表插入數據");
}
public void update() {
System.out.println("Oracle 對角色表更新數據");
}
}
// 角色表MySql資料庫DAO
class MySqlroleDAO implements IroleDao {
public void insert() {
System.out.println("MySql 對角色表插入數據");
}
public void update() {
System.out.println("Mysql 對角色表更新數據");
}
}
這里增加了一套DAO的實現 (與平時有所不同,如果有10個資料庫就要加上10種不同的實現,比較麻煩呀)
3.定義DAO工廠介面與實現(利用java反射機制生產出你需要的DAO如:userDAO,roleDao)
Java代碼
// DAO工廠
abstract class DaoFactory {
public static DaoFactory getInstance(String classname) {
DaoFactory = null;
try {
= (DaoFactory) Class.forName(classname).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return ;
}
abstract IuserDao getuser();
abstract IroleDao getrole();
}
// Oralce工廠
class OracleFactory extends DaoFactory {
public IroleDao getrole() {
return new OracleroleDao();
}
public IuserDao getuser() {
return new OracleuserDao();
}
}
// MySql工廠
class MysqlFactory extends DaoFactory {
public IroleDao getrole() {
return new MySqlroleDAO();
}
public IuserDao getuser() {
return new MySqluserDao();
}
}
// DAO工廠
abstract class DaoFactory {
public static DaoFactory getInstance(String classname) {
DaoFactory = null;
try {
= (DaoFactory) Class.forName(classname).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return ;
}
abstract IuserDao getuser();
abstract IroleDao getrole();
}
// Oralce工廠
class OracleFactory extends DaoFactory {
public IroleDao getrole() {
return new OracleroleDao();
}
public IuserDao getuser() {
return new OracleuserDao();
}
}
// MySql工廠
class MysqlFactory extends DaoFactory {
public IroleDao getrole() {
return new MySqlroleDAO();
}
public IuserDao getuser() {
return new MySqluserDao();
}
}
4. 定義配置文件
Java代碼
class Config {
// Oralce
static final String ORALCE = "org.abc.OracleFactory";
static final String MYSQL = "org.abc.MysqlFactory";
}
class Config {
// Oralce
static final String ORALCE = "org.abc.OracleFactory";
static final String MYSQL = "org.abc.MysqlFactory";
}
配置文件可以定義到XML中去(好處:修改配置項之後不需要對JAVA文件進行編譯.)
5.測試你的輸出的DAO
Java代碼
public class Dao {
public static void main(String[] args) {
DaoFactory.getInstance(Config.ORALCE).getrole().insert();
DaoFactory.getInstance(Config.MYSQL).getrole().insert();
}
}
public class Dao {
public static void main(String[] args) {
DaoFactory.getInstance(Config.ORALCE).getrole().insert();
DaoFactory.getInstance(Config.MYSQL).getrole().insert();
}
}
總結
使用條件:一系列介面有一系列的實現
如上IuserDao、IroleDao等一系列的介面,他們可以有一系列的實現(Oracle方式、MySql方式)
OracleuserDao、OracleroleDao、MySqluserDao、MySqlroleDAO
組成元素(以上面例子)
一系列介面:IuserDao、IroleDao
一系列實現:Oracle系列、MySql系列
系列工廠類:Oracle系列工廠類、MySql系列工廠類(必須繼承抽象工廠類)
抽象工廠類:DaoFactory
❿ 什麼是抽象工廠
工廠模式定義:提供創建對象的介面.
為何使用?
工廠模式是我們最常用的模式了,著名的Jive論壇 ,就大量使用了工廠模式,工廠模式在Java程序系統可以說是隨處可見。
為什麼工廠模式是如此常用?因為工廠模式就相當於創建實例對象的new,我們經常要根據類Class生成實例對象,如A a=new A() 工廠模式也是用來創建實例對象的,所以以後new時就要多個心眼,是否可以考慮實用工廠模式,雖然這樣做,可能多做一些工作,但會給你系統帶來更大的可擴展性和盡量少的修改量。
我們以類Sample為例, 如果我們要創建Sample的實例對象:
Sample sample=new Sample();
可是,實際情況是,通常我們都要在創建sample實例時做點初始化的工作,比如賦值 查詢資料庫等。
首先,我們想到的是,可以使用Sample的構造函數,這樣生成實例就寫成:
Sample sample=new Sample(參數);
但是,如果創建sample實例時所做的初始化工作不是象賦值這樣簡單的事,可能是很長一段代碼,如果也寫入構造函數中,那你的代碼很難看了(就需要Refactor重整)。
為什麼說代碼很難看,初學者可能沒有這種感覺,我們分析如下,初始化工作如果是很長一段代碼,說明要做的工作很多,將很多工作裝入一個方法中,相當於將很多雞蛋放在一個籃子里,是很危險的,這也是有背於Java面向對象的原則,面向對象的封裝(Encapsulation)和分派(Delegation)告訴我們,盡量將長的代碼分派「切割」成每段,將每段再「封裝」起來(減少段和段之間偶合聯系性),這樣,就會將風險分散,以後如果需要修改,只要更改每段,不會再發生牽一動百的事情。
在本例中,首先,我們需要將創建實例的工作與使用實例的工作分開, 也就是說,讓創建實例所需要的大量初始化工作從Sample的構造函數中分離出去。
這時我們就需要Factory工廠模式來生成對象了,不能再用上面簡單new Sample(參數)。還有,如果Sample有個繼承如MySample, 按照面向介面編程,我們需要將Sample抽象成一個介面.現在Sample是介面,有兩個子類MySample 和HisSample .我們要實例化他們時,如下:
Sample mysample=new MySample();
Sample hissample=new HisSample();
隨著項目的深入,Sample可能還會"生出很多兒子出來", 那麼我們要對這些兒子一個個實例化,更糟糕的是,可能還要對以前的代碼進行修改:加入後來生出兒子的實例.這在傳統程序中是無法避免的.
但如果你一開始就有意識使用了工廠模式,這些麻煩就沒有了.
工廠方法
你會建立一個專門生產Sample實例的工廠:
public class Factory{
public static Sample creator(int which){
//getClass 產生Sample 一般可使用動態類裝載裝入類。
if (which==1)
return new SampleA();
else if (which==2)
return new SampleB();
}
}
那麼在你的程序中,如果要實例化Sample時.就使用
Sample sampleA=Factory.creator(1);
這樣,在整個就不涉及到Sample的具體子類,達到封裝效果,也就減少錯誤修改的機會,這個原理可以用很通俗的話來比喻:就是具體事情做得越多,越容易范錯誤.這每個做過具體工作的人都深有體會,相反,官做得越高,說出的話越抽象越籠統,范錯誤可能性就越少.好象我們從編程序中也能悟出人生道理?呵呵.
使用工廠方法 要注意幾個角色,首先你要定義產品介面,如上面的Sample,產品介面下有Sample介面的實現類,如SampleA,其次要有一個factory類,用來生成產品Sample,如下圖,最右邊是生產的對象Sample:
進一步稍微復雜一點,就是在工廠類上進行拓展,工廠類也有繼承它的實現類concreteFactory了。
抽象工廠
工廠模式中有: 工廠方法(Factory Method) 抽象工廠(Abstract Factory).
這兩個模式區別在於需要創建對象的復雜程度上。如果我們創建對象的方法變得復雜了,如上面工廠方法中是創建一個對象Sample,如果我們還有新的產品介面Sample2.
這里假設:Sample有兩個concrete類SampleA和SamleB,而Sample2也有兩個concrete類Sample2A和SampleB2
那麼,我們就將上例中Factory變成抽象類,將共同部分封裝在抽象類中,不同部分使用子類實現,下面就是將上例中的Factory拓展成抽象工廠:
public abstract class Factory{
public abstract Sample creator();
public abstract Sample2 creator(String name);
}
public class SimpleFactory extends Factory{
public Sample creator(){
.........
return new SampleA
}
public Sample2 creator(String name){
.........
return new Sample2A
}
}
public class BombFactory extends Factory{
public Sample creator(){
......
return new SampleB
}
public Sample2 creator(String name){
......
return new Sample2B
}
}
從上面看到兩個工廠各自生產出一套Sample和Sample2,也許你會疑問,為什麼我不可以使用兩個工廠方法來分別生產Sample和Sample2?
抽象工廠還有另外一個關鍵要點,是因為 SimpleFactory內,生產Sample和生產Sample2的方法之間有一定聯系,所以才要將這兩個方法捆綁在一個類中,這個工廠類有其本身特徵,也許製造過程是統一的,比如:製造工藝比較簡單,所以名稱叫SimpleFactory。
在實際應用中,工廠方法用得比較多一些,而且是和動態類裝入器組合在一起應用,
舉例
我們以Jive的ForumFactory為例,這個例子在前面的Singleton模式中我們討論過,現在再討論其工廠模式:
public abstract class ForumFactory {
private static Object initLock = new Object();
private static String className = "com.jivesoftware.forum.database.DbForumFactory";
private static ForumFactory factory = null;
public static ForumFactory getInstance(Authorization authorization) {
//If no valid authorization passed in, return null.
if (authorization == null) {
return null;
}
//以下使用了Singleton 單態模式
if (factory == null) {
synchronized(initLock) {
if (factory == null) {
......
try {
//動態轉載類
Class c = Class.forName(className);
factory = (ForumFactory)c.newInstance();
}
catch (Exception e) {
return null;
}
}
}
}
//Now, 返回 proxy.用來限制授權對forum的訪問
return new ForumFactoryProxy(authorization, factory,
factory.getPermissions(authorization));
}
//真正創建forum的方法由繼承forumfactory的子類去完成.
public abstract Forum createForum(String name, String description)
throws UnauthorizedException, ForumAlreadyExistsException;
....
}
因為現在的Jive是通過資料庫系統存放論壇帖子等內容數據,如果希望更改為通過文件系統實現,這個工廠方法ForumFactory就提供了提供動態介面:
private static String className = "com.jivesoftware.forum.database.DbForumFactory";
你可以使用自己開發的創建forum的方法代替com.jivesoftware.forum.database.DbForumFactory就可以.
在上面的一段代碼中一共用了三種模式,除了工廠模式外,還有Singleton單態模式,以及proxy模式,proxy模式主要用來授權用戶對forum的訪問,因為訪問forum有兩種人:一個是注冊用戶 一個是遊客guest,那麼那麼相應的許可權就不一樣,而且這個許可權是貫穿整個系統的,因此建立一個proxy,類似網關的概念,可以很好的達到這個效果.
看看Java寵物店中的CatalogDAOFactory:
public class CatalogDAOFactory {
/**
* 本方法制定一個特別的子類來實現DAO模式。
* 具體子類定義是在J2EE的部署描述器中。
*/
public static CatalogDAO getDAO() throws CatalogDAOSysException {
CatalogDAO catDao = null;
try {
InitialContext ic = new InitialContext();
//動態裝入CATALOG_DAO_CLASS
//可以定義自己的CATALOG_DAO_CLASS,從而在無需變更太多代碼
//的前提下,完成系統的巨大變更。
String className =(String) ic.lookup(JNDINames.CATALOG_DAO_CLASS);
catDao = (CatalogDAO) Class.forName(className).newInstance();
} catch (NamingException ne) {
throw new CatalogDAOSysException("
CatalogDAOFactory.getDAO: NamingException while
getting DAO type : \n" + ne.getMessage());
} catch (Exception se) {
throw new CatalogDAOSysException("
CatalogDAOFactory.getDAO: Exception while getting
DAO type : \n" + se.getMessage());
}
return catDao;
}
}
CatalogDAOFactory是典型的工廠方法,catDao是通過動態類裝入器className獲得CatalogDAOFactory具體實現子類,這個實現子類在Java寵物店是用來操作catalog資料庫,用戶可以根據資料庫的類型不同,定製自己的具體實現子類,將自己的子類名給與CATALOG_DAO_CLASS變數就可以。
由此可見,工廠方法確實為系統結構提供了非常靈活強大的動態擴展機制,只要我們更換一下具體的工廠方法,系統其他地方無需一點變換,就有可能將系統功能進行改頭換面的變化。
設計模式如何在具體項目中應用見《Java實用系統開發指南》
文章地址:
http://www.jdon.com/designpatterns/designpattern_factory.htm
http://zh.wikipedia.org/wiki/%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F
http://www.cnblogs.com/yuyijq/archive/2007/10/06/915185.html