簡單工廠模式,工廠方法模式,抽象工廠模式,spring的狂想

? ? ? 菜鳥D在項目中遇見一個比較糾結的高耦合,所以就想辦法來解耦。情況是這樣的:系統通過用戶選擇treeview控件的節點判斷調用不同的處理,這些處理中某些東西又是類似的。同事的建議是采用簡單工廠,耦合就耦合吧,反正treeview節點基本是不會變化的。(能偷懶就偷懶吧)

? ? ? 菜鳥D有些偏執,想找些方法來解耦。于是就學習了這個幾種方法,雖然不一定用的上,多學一點總是好的。

? ? ? 首先說簡單工廠,例子是一個已經二到死的計算器。

? ? ? 簡單工廠由三種角色組成:工廠類角色(creator),抽象產品類角色(product,圖中為Iproduct接口),具體產品類角色(concreteproduct,圖中為Product_A…)。

? ? 代碼如下:

public class Calculate{public double DValue1 { get; set; }public double DValue2 { get; set; }public virtual double GetResult(){return 0;}}public class Add : Calculate{public override double GetResult(){return DValue1 + DValue2;}}public class Sub : Calculate{public override double GetResult(){return DValue1 - DValue2;}}public class Mul : Calculate{public override double GetResult(){return DValue1 * DValue2;}}public class Div : Calculate{public override double GetResult(){if (DValue2.Equals(0)){if (DValue1.Equals(0)){return 1;}return 0;}return DValue1 / DValue2;}}
基本的代碼
            #region 客戶端Console.WriteLine("請輸入第一個數");string v1 = Console.ReadLine();Console.WriteLine("請輸入運算符");string oper = Console.ReadLine();Console.WriteLine("請輸入第二個數");string v2 = Console.ReadLine();Calculate c = GetCalculateByOper(oper);c.DValue1 = Convert.ToDouble(v1);c.DValue2 = Convert.ToDouble(v2);Console.WriteLine("結果:" + c.GetResult()); #endregion#region 工廠方法private static Calculate GetCalculateByOper(string oper){Calculate c = new Calculate();switch (oper){case "+": c = new Add();break;case "-": c = new Sub();break;case "*": c = new Mul();break;case "/": c = new Div();break;}return c;} #endregion    

? ? ? 在這個例子中沒有使用抽象類,接口,而是用了虛方法(純粹是不想在接口里定義屬性,自己喜歡用什么就用什么,畢竟這不是簡單工廠的核心)。簡單工廠的核心是充當工廠類角色的工廠方法(起碼在此例中是這樣),邏輯判斷中使具體產品類和工廠直接耦合了(好像類圖的關系已經決定了這種耦合,但是將具體產品和客戶端解耦)。如果要添加一個開方運算,首先添加開方的運算類,然后打開工廠方法進行修改。(呵呵,違反了開閉原則)

? ? ?接下來再說一下工廠方法模式,類圖如下:

? ? ? 先分析一下類圖,工廠模式有了四個角色:工廠接口,工廠實現,產品接口,產品實現(其實說角色不貼切,還不如說是種類)。工廠實現和產品實現有了依賴關系,通過調用工廠實現來獲取產品實現。也就是一種產品實現對應一種工廠實現。

? ? ?還是那個二的要死的計算器的例子,代碼如下:

    public interface IFactory{ICalculatable GetCalculatable();}public interface ICalculatable{double GetReslut(double d1, double d2);}public class Add : ICalculatable{public double GetReslut(double d1, double d2){return d1 + d2;}}public class AddFactory : IFactory{public ICalculatable GetCalculatable(){return new Add();}}public class Sub : ICalculatable{public double GetReslut(double d1, double d2){return d1 - d2;}}public class SubFactory : IFactory{public ICalculatable GetCalculatable(){return new Sub();}}public class Mul : ICalculatable{public double GetReslut(double d1, double d2){return d1 * d2;}}public class MulFactory : IFactory{public ICalculatable GetCalculatable(){return new Mul();}}public class Div : ICalculatable{public double GetReslut(double d1, double d2){if (d2.Equals(0)){if (d1.Equals(0)){return 1;}return 0;}return d1 / d2;}}public class DivFactory : IFactory{public ICalculatable GetCalculatable(){return new Div();}}
基本代碼
#region 邏輯判斷public class Factory{public static IFactory GetCalculatableByOper(string oper){IFactory factory = null;switch (oper){case "+": factory = new AddFactory();break;case "-": factory = new SubFactory();break;case "*": factory = new MulFactory();break;case "/": factory = new DivFactory();break;}return factory == null ? null : factory;}} 
#endregion#region 客戶端Console.WriteLine("請輸入第一個數");string v1 = Console.ReadLine();Console.WriteLine("請輸入運算符");string oper = Console.ReadLine();Console.WriteLine("請輸入第二個數");string v2 = Console.ReadLine();ICalculatable calculatable = Factory.GetCalculatableByOper(oper).GetCalculatable();Console.WriteLine("結果:" + calculatable.GetReslut(Convert.ToDouble(v1), Convert.ToDouble(v2))); #endregion

? ? ? 注意:此處的判斷邏輯已經不屬于工廠模式了(類圖中很明確),也可以脫離客戶端。雖說簡單工廠也可以這樣將判斷邏輯脫離客戶端,但是簡單工廠的邏輯判斷是在工廠類中的,也就依然是簡單工廠模式的一部分(此處邏輯有些亂,不懂的就認真研究類圖)。通常在工廠模式的客戶端需要用到哪種工廠再去創建哪種工廠,而不是如例子中的使用一個判斷邏輯來選擇,也就是工廠模式創建工廠是通過“外部”的邏輯來確定,而模式本身是不會做判斷的。(所以這個例子并不是一個合適的例子)

? ? ? 此時,計算器要再添加一個開方的方法,只需添加方法實現,添加工廠實現,不會對原有的代碼做修改,符合了開閉原則(你當我瞎啊,你不修改判斷邏輯嗎?說了多少次了,判斷邏輯部分不屬于工廠模式。不過比簡單工廠確實多寫不少東西)。

? ? ? 工廠方法模式通常在以下兩種情況中使用 :

? ? ? 第一,需要使用某種產品,客戶端很清楚應該使用哪個具體工廠,此種情況不存在上述的判斷邏輯,只需要實例化具體工廠,然后生產具體產品。

? ? ? 第二,需要使用某種產品,但是不想也不需要知道是哪個工廠創建,此種情況存在一定的判斷邏輯,但是客戶端不需要知道這個邏輯,生產方(工廠模式)是通過外部的邏輯來生產產品,這時由外部來實例化具體工廠,生產具體產品交付給客戶端。

? ? ? 接著再來說說抽象工廠,在抽象工廠中最明顯的一個特點是產品不止一類了,所以前文提到的計算機的例子就不適合使用抽象工廠模式(竊以為如此,有反對意見的歡迎提出)。

? ? ? 在抽象工廠在提到一個“產品族”的概念,其實在抽象工廠中最為直觀的體現就是產品A接口,產品B接口甚至是產品C、D接口。類圖如下,從類圖中不難發現,抽象工廠模式的具體工廠角色可以生產多種產品(工廠方法模式的具體工廠只能生產一種產品,不信去看類圖)。就好像東方紅拖拉機廠在工廠方法模式下只能生產拖拉機,但是在抽象工廠模式下不僅能生產拖拉機,還能生產卡車(如果加一個坦克的生產線,還能生產坦克)。

? ? ? 此處就用比較熟悉的農場的例子,農場生產水果和蔬菜,水果分為北方水果和熱帶水果,蔬菜也一樣,所以農場也分為北方農場和熱帶農場。

? ? ? 代碼如下:

    public interface IFruit{string Show();}public interface IVeggie{string Show();}public class NFruit : IFruit{private string name;public string Name{get { return "北方" + name; }set { name = value; }}public string Show(){return Name;}}public class TFruit : IFruit{string name;public string Name{get { return "熱帶" + name; }set { name = value; }}public string Show(){return Name;}}public class NVeggie : IVeggie{string name;public string Name{get { return "北方" + name; }set { name = value; }}public string Show(){return Name;}}public class TVeggie : IVeggie{string name;public string Name{get { return "熱帶" + name; }set { name = value; }}public string Show(){return Name;}}public interface Factory{IFruit CreateFruit(string nm);IVeggie CreateVeggie(string nm);}public class NFactory : Factory{public IFruit CreateFruit(string nm){return new NFruit() { Name = nm };}public IVeggie CreateVeggie(string nm){return new NVeggie() { Name = nm };}}public class TFactory : Factory{public IFruit CreateFruit(string nm){return new TFruit() { Name = nm };}public IVeggie CreateVeggie(string nm){return new TVeggie() { Name = nm };}}
基本代碼

? ? ? 此例的邏輯判斷部分沒寫。從類圖上看,它是不屬于抽象工廠模式的,從簡化客戶端的角度,這個邏輯判斷是可以從客戶端剝離的,很顯然和工廠方法模式的邏輯判斷屬于同一地位(有種兩頭受氣的感覺)。

? ? ?然后再簡單說spring的依賴注入。在spring中需要獲取一個產品(實例)如何獲取?容器來提供。邏輯判斷呢?可以放在客戶端,也可以從客戶端剝離,愛放哪放哪。容器只依賴于配置,邏輯判斷不會影響容器。所以容器很好的將生產過程與客戶端隔離,這就不存在耦合了。

? ? ? 接下來再說一下,一直不停的重復的判斷邏輯。在菜鳥D 的看法里,上述幾個模式的耦合都是存在于判斷邏輯中的。在簡單工廠中,工廠和客戶端之間耦合較低,但是工廠和具體的產品類是直接耦合的。在工廠方法模式、抽象工廠模式、spring中,邏輯判斷只是一個輔助,邏輯判斷將生產過程和客戶端隔離,大大地降低了耦合程度。所以在衡量設計模式的耦合時,就需要衡量判斷邏輯在模式中作用和角色。有些耦合是很難避免的,為了避免這些耦合甚至可能會造成更多的耦合。至于開閉原則,編碼過程盡量去注意,否則為以后的開發帶來麻煩就不是我們想要的了。

? ? ?一家之言,不值一哂,如有謬誤,歡迎指正。

? ? ?菜鳥D希望這篇文章對您有所幫助。

擴展參考:

大話設計模式P72:

? ? ? 工廠方法實現時,客戶端需要決定實例化哪一個工廠來實現運算類(具體產品),選擇判斷的問題還是存在的,也就是說,工廠方法吧簡單工廠的內部邏輯判斷移到了客戶端代碼來進行.想要添加功能,本來是要改工廠類的,而現在是修改客戶端.

三種工廠模式區別總結

http://blog.csdn.net/lingfengtengfei/article/details/12374469

spring.net的依賴注入

http://www.cnblogs.com/GoodHelper/archive/2009/10/26/SpringNET_DI.html

工廠方法模式

http://blog.csdn.net/zhengzhb/article/details/7348707

三種工廠模式

http://www.cnblogs.com/poissonnotes/archive/2010/12/01/1893871.html

?

轉載于:https://www.cnblogs.com/cnDqf/p/4122771.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/259689.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/259689.shtml
英文地址,請注明出處:http://en.pswp.cn/news/259689.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

堆、棧及靜態數據區詳解 轉

內存分為代碼區、全局數據區、堆區和棧區。堆一般存放動態數據,棧里一般存放局部成員。 關于堆棧和堆的概念[問題] C中創建本地(或者說局域)變量是在堆棧(stack)中分配內存地址,而創建全局變量則是在堆&…

如何使用CSS實現居中

前言: 這一篇主要是翻譯 《how-to-center-anything-with-css》這一篇文章的主要內容,再加上自己的一些概括理解;主要問題是解決垂直居中的問題。我們知道實現水平居中的方式很多種,比如: text-align:center; margin:0 …

java布局_運用 BoxLayout 進行 Swing 控件布局

引言在用戶使用 Java Swing 進行用戶界面開發過程中,會碰到如何對 Java Swing 的控件進行布局的問題。Swing 的控件放置在容器 (Container) 中,容器就是能夠容納控件或者其它容器的類,容器的具體例子有 Frame、Panel 等等。容器需要定義一個布…

js變量類型

js中有null和undefined,null是指對象不存在,undefined是指原生數據不存在 var h {name:lisi,age:28};console.log(h.name)//對象用的是點語法,php中是name->lisi 下面是數組,數組用的是【】語法 1 var arr [a,3,hello,true];…

OPENCV MFC 程序出錯修改

error C2146: 語法錯誤 : 缺少“;”(在標識符“PVOID64”的前面) 來源:http://houjixin.blog.163.com/blog/static/356284102009112395049370/ DirectShow 2009-12-23 09:50:49 閱讀311 評論0 字號:大中小打開winnt.h文件,發現問題就是在winnt.h頭文件中…

測試人員報BUG的正確姿勢

每次我提需求的時候,都會和開發一言不合就上BUG。曾經看到一個段子,告訴了我,吵架是不行滴!影響心情,正確報bug的姿勢應該是這樣:不要對程序員說,你的代碼有BUG。他的第一反應是:1、…

java鏈表實現_鏈表的原理及java實現

一:單向鏈表基本介紹鏈表是一種數據結構,和數組同級。比如,Java中我們使用的ArrayList,其實現原理是數組。而LinkedList的實現原理就是鏈表了。鏈表在進行循環遍歷時效率不高,但是插入和刪除時優勢明顯。下面對單向鏈表…

python和django中的常見錯誤

int() argument must be a string or a number, not tupleError in formatting: coercing to Unicode: need string or buffer, int foundData truncated for column content at row 1sql語句中單引號的設置字段類型字段長度 ascii codec cant decode byte 0xe7 in position 0:…

20141126-解決聯網問題-筆記

當你的網絡出現故障或無法連通時,如何才能簡單高效的找出故障?其實只需要一個ping命令,就可以判斷TCP/IP協議故障…… 1、Ping 127.0.0.1: 127.0.0.1是本地循環地址,如果本地址無法Ping通,則表明本地機TCP/…

inittab腳本啟動解析 (zz)

http://blog.chinaunix.net/uid-17188120-id-4073497.html 1,啟動inittab第一步:啟動內核第二步:執行init (配置文件/etc/inittab)第三步:啟動相應的腳本,執行inittab腳本,并且執行其…

java緩存技術_java緩存技術

最近在做java緩存,了解了一下.以下僅是對map對方式討論。沒有對點陣圖陣討論。作緩存要做以下2點:1:清理及更新緩存時機的處理:. 虛擬機內存不足,清理緩存.. 緩存時間超時,或訪問次數超出, 啟動線程更新2:類和方法的反射 (線程嵌套調用)reflect.invoke的使用。代碼如下&#xf…

xss challenge 解題思路(1-3)

challenge1: 用很基本的方法即可&#xff0c;截圖如下&#xff1a; 提交后成功彈窗&#xff0c;完成。 challenge2 這次我們發現我們輸入的內容被放入value”“ 中&#xff0c;所以需要將前面的結構閉合&#xff0c;構造如下&#xff1a; "><script>alert(docume…

賓得準餅干廣角鏡頭DA15

DA15的掛機效果圖&#xff0c;感覺還是超級的小&#xff0c;是最小的廣角鏡頭了&#xff1a; 主要特點1. 超廣視角當安裝在賓得數碼單反相機上時&#xff0c;這款全新的鏡頭提供相當于35mm膠片規格的約23mm畫面視角&#xff0c;可使拍攝者拍攝出獨特的誘人影像和超廣角鏡頭獨有…

無限“遞歸”的python程序

如果一個函數直接或者間接調用了自己&#xff0c;那么就形成了遞歸&#xff08;recursion&#xff09;&#xff0c;比如斐波那契數列的一個實現 def fib(n):if n < 2:return 1else:return fib(n - 1) fib(n - 2) 遞歸一定要有結束條件&#xff0c;否則就形成了死循環&#…

java slf4j_SLF4J 使用手冊

原文鏈接 譯者&#xff1a;zivyuJava的簡單日志門面( Simple Logging Facade for Java SLF4J)作為一個簡單的門面或抽象&#xff0c;用來服務于各種各樣的日志框架&#xff0c;比如java.util.logging、logback和log4j。SLF4J允許最終用戶在部署時集成自己想要的日志框架。需要…

[譯]Java 垃圾回收介紹

說明&#xff1a;這篇文章來翻譯來自于Javapapers 的Java Garbage Collection Introduction 在Java中&#xff0c;對象內存空間的分配與回收是由JVM中的垃圾回收進程自動完成的。和C語言不一樣的是&#xff0c;開發中不需要在Java中寫垃圾回收代碼。這也是使Java更加流行而且幫…

打印三角形

直角三角形 #include<iostream> using namespace std; int main() { int i,j; for(i1;i<10;i) {for(j1;j<i;j) cout<<"*"; cout<<endl; } } ———————————————————————————…

Linux基礎入門學習筆記之二

第三節 用戶及文件權限管理 Linux用戶管理 Linux是可以實現多用戶登錄的操作系統 查看用戶who命令用于查看用戶 shiyanlou是當前登錄用戶的用戶名 pts/0中pts表示偽終端&#xff0c;后面的數字表示偽終端的序號。 后面是當前偽終端啟動時間 創建用戶創建用戶需要root權限&#…

java選填_java基礎填空選擇題

Core Java試題選擇填空題&#xff1a;全部為多選題&#xff0c;只有全部正確才能得分。1. 編譯java程序的命令是__B_;運行java程序的命令是____A____;產生java文擋的命令是_____D___;查詢java類型是否是serializable類型的命令是___C_____;產生java安全策略文件的命令是____E__…

這幾天有django和python做了一個多用戶博客系統(可選擇模板) 沒完成,先分享下...

這個TBlog已經全新改版了&#xff0c;更名為UUBlog 新版地址&#xff1a; 用Python和Django實現多用戶博客系統——UUBlog 斷斷續續2周時間吧&#xff0c;用django做了一個多用戶博客系統&#xff0c;現在還沒有做完&#xff0c;做分享下,以后等完善了再慢慢說 做的時候房展了博…