<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          java設計模式之工廠模式

          共 13496字,需瀏覽 27分鐘

           ·

          2022-07-23 16:44

          作者:zailushang1996
          來源:cnblogs.com/zailushang1996

          一、簡單工廠模式

          一個栗子: 
          我喜歡吃面條,抽象一個面條基類,(接口也可以),這是產品的抽象類。

          public abstract class INoodles {
             /**
              * 描述每種面條啥樣的
              */

             public abstract void desc();
          }

          先來一份蘭州拉面(具體的產品類):

          public class LzNoodles extends INoodles {
             @Override
             public void desc() {
                 System.out.println("蘭州拉面 上海的好貴 家里才5 6塊錢一碗");
             }
          }

          程序員加班必備也要吃泡面(具體的產品類):

          public class PaoNoodles extends INoodles {
             @Override
             public void desc() {
                 System.out.println("泡面好吃 可不要貪杯");
             }
          }

          還有我最愛吃的家鄉(xiāng)的干扣面(具體的產品類):

          public class GankouNoodles extends INoodles {
             @Override
             public void desc() {
                 System.out.println("還是家里的干扣面好吃 6塊一碗");
             }
          }

          準備工作做完了,我們來到一家“簡單面館”(簡單工廠類),菜單如下:

          public class SimpleNoodlesFactory {
             public static final int TYPE_LZ = 1;//蘭州拉面
             public static final int TYPE_PM = 2;//泡面
             public static final int TYPE_GK = 3;//干扣面
             public static INoodles createNoodles(int type) {
                 switch (type) {
                     case TYPE_LZ:
                         return new LzNoodles();
                     case TYPE_PM:
                         return new PaoNoodles();
                     case TYPE_GK:
                     default:
                         return new GankouNoodles();
                 }
             }
          }

          簡單面館就提供三種面條(產品),你說你要啥,他就給你啥。這里我點了一份干扣面:

          /**
          * 簡單工廠模式
          */

          INoodles noodles = SimpleNoodlesFactory.createNoodles(SimpleNoodlesFactory.TYPE_GK);
          noodles.desc();

          輸出:

          還是家里的干扣面好吃 6塊一碗

          特點
          1 它是一個具體的類,非接口 抽象類。有一個重要的create()方法,利用if或者 switch創(chuàng)建產品并返回。
          2 create()方法通常是靜態(tài)的,所以也稱之為靜態(tài)工廠。

          缺點
          1 擴展性差(我想增加一種面條,除了新增一個面條產品類,還需要修改工廠類方法)
          2 不同的產品需要不同額外參數(shù)的時候 不支持。

          二、工廠方法模式

          1.模式描述

          提供一個用于創(chuàng)建對象的接口(工廠接口),讓其實現(xiàn)類(工廠實現(xiàn)類)決定實例化哪一個類(產品類),并且由該實現(xiàn)類創(chuàng)建對應類的實例。

          2.模式作用

          可以一定程度上解耦,消費者和產品實現(xiàn)類隔離開,只依賴產品接口(抽象產品),產品實現(xiàn)類如何改動與消費者完全無關。

          可以一定程度增加擴展性,若增加一個產品實現(xiàn),只需要實現(xiàn)產品接口,修改工廠創(chuàng)建產品的方法,消費者可以無感知(若消費者不關心具體產品是什么的情況)。
          可以一定程度增加代碼的封裝性、可讀性。清楚的代碼結構,對于消費者來說很少的代碼量就可以完成很多工作。
          等等。//TODO
          另外,抽象工廠才是實際意義的工廠模式,工廠方法只是抽象工廠的一個比較常見的情況。

          3.適用場景

          消費者不關心它所要創(chuàng)建對象的類(產品類)的時候。

          消費者知道它所要創(chuàng)建對象的類(產品類),但不關心如何創(chuàng)建的時候。

          例如:hibernate里通過sessionFactory創(chuàng)建session、通過代理方式生成ws客戶端時,通過工廠構建報文中格式化數(shù)據(jù)的對象。

          4.模式要素

          提供一個產品類的接口。產品類均要實現(xiàn)這個接口(也可以是abstract類,即抽象產品)。
          提供一個工廠類的接口。工廠類均要實現(xiàn)這個接口(即抽象工廠)。
          由工廠實現(xiàn)類創(chuàng)建產品類的實例。工廠實現(xiàn)類應有一個方法,用來實例化產品類。

          5.類圖

          6.模式實例代碼

          工廠:

          package com.demoFound.factoryMethod.factory;  
          import com.demoFound.factoryMethod.message.IMyMessage;  
          /**
          * 工廠方法模式_工廠接口
          *  
          * @author popkidorc
          *  
          */
           
          public interface IMyMessageFactory {  
             public IMyMessage createMessage(String messageType);  
          }

          package com.demoFound.factoryMethod.factory;  
          import java.util.HashMap;  
          import java.util.Map;  
          import com.demoFound.factoryMethod.message.IMyMessage;  
          import com.demoFound.factoryMethod.message.MyMessageEmail;  
          import com.demoFound.factoryMethod.message.MyMessageOaTodo;  
          import com.demoFound.factoryMethod.message.MyMessageSms;  
          /**
          * 工廠方法模式_工廠實現(xiàn)
          *  
          * @author popkidorc
          *  
          */
           
          public class MyMessageFactory implements IMyMessageFactory {  
             @Override  
             public IMyMessage createMessage(String messageType) {  
                 // 這里的方式是:消費者知道自己想要什么產品;若生產何種產品完全由工廠決定,則這里不應該傳入控制生產的參數(shù)。 
                 IMyMessage myMessage;  
                 Map<String, Object> messageParam = new HashMap<String, Object>();  
                 // 根據(jù)某些條件去選擇究竟創(chuàng)建哪一個具體的實現(xiàn)對象,條件可以傳入的,也可以從其它途徑獲取。 
                 // sms  
                 if ("SMS".equals(messageType)) {  
                     myMessage = new MyMessageSms();  
                     messageParam.put("PHONENUM", "123456789");  
                 } else  
                 // OA待辦  
                 if ("OA".equals(messageType)) {  
                     myMessage = new MyMessageOaTodo();  
                     messageParam.put("OAUSERNAME", "testUser");  
                 } else  
                 // email  
                 if ("EMAIL".equals(messageType)) {  
                     myMessage = new MyMessageEmail();  
                     messageParam.put("EMAIL", "[email protected]");  
                 } else  
                 // 默認生產email這個產品  
                 {  
                     myMessage = new MyMessageEmail();  
                     messageParam.put("EMAIL", "[email protected]");  
                 }  
                 myMessage.setMessageParam(messageParam);  
                 return myMessage;  
             }  
          }

          產品:

          package com.demoFound.factoryMethod.message;  
          import java.util.Map;  
          /**
          * 工廠方法模式_產品接口
          *  
          * @author popkidorc
          *  
          */
           
          public interface IMyMessage {  
             public Map<String, Object> getMessageParam();  
             public void setMessageParam(Map<String, Object> messageParam);  
             public void sendMesage() throws Exception;// 發(fā)送通知/消息  
          }

          package com.demoFound.factoryMethod.message;  
          import java.util.Map;  
          /**
          * 工廠方法模式_虛擬產品類
          *  
          * @author popkidorc
          *  
          */
           
          public abstract class MyAbstractMessage implements IMyMessage {  
             private Map<String, Object> messageParam;// 這里可以理解為生產產品所需要的原材料庫。最好是個自定義的對象,這里為了不引起誤解使用Map。 
             @Override  
             public Map<String, Object> getMessageParam() {  
                 return messageParam;  
             }  
             @Override  
             public void setMessageParam(Map<String, Object> messageParam) {  
                 this.messageParam = messageParam;  
             }  
          }

          package com.demoFound.factoryMethod.message;  
          /**
          * 工廠方法模式_email產品
          *  
          * @author popkidorc
          *  
          */
           
          public class MyMessageEmail extends MyAbstractMessage {  
             @Override  
             public void sendMesage() throws Exception
          {  
                 // TODO Auto-generated method stub  
                 if (null == getMessageParam() || null == getMessageParam().get("EMAIL")  
                         || "".equals(getMessageParam().get("EMAIL"))) {  
                     throw new Exception("發(fā)送短信,需要傳入EMAIL參數(shù)");// 為了簡單起見異常也不自定義了  
                 }// 另外郵件內容,以及其他各種協(xié)議參數(shù)等等都要處理  
                 System.out.println("我是郵件,發(fā)送通知給" + getMessageParam().get("EMAIL"));  
             }  
          }

          package com.demoFound.factoryMethod.message;  
          /**
          * 工廠方法模式_oa待辦產品
          *  
          * @author popkidorc
          *  
          */
           
          public class MyMessageOaTodo extends MyAbstractMessage {  
             @Override  
             public void sendMesage() throws Exception
          {  
                 // TODO Auto-generated method stub  
                 if (null == getMessageParam()  
                         || null == getMessageParam().get("OAUSERNAME")  
                         || "".equals(getMessageParam().get("OAUSERNAME"))) {  
                     throw new Exception("發(fā)送OA待辦,需要傳入OAUSERNAME參數(shù)");// 為了簡單起見異常也不自定義了  
                 }// 這里的參數(shù)需求就比較多了不一一處理了  
                 System.out  
                         .println("我是OA待辦,發(fā)送通知給" + getMessageParam().get("OAUSERNAME"));  
             }  
          }

          package com.demoFound.factoryMethod.message;  
          /**
          * 工廠方法模式_sms產品
          *  
          * @author popkidorc
          *  
          */
           
          public class MyMessageSms extends MyAbstractMessage {  
             @Override  
             public void sendMesage() throws Exception
          {  
                 // TODO Auto-generated method stub  
                 if (null == getMessageParam()  
                         || null == getMessageParam().get("PHONENUM")  
                         || "".equals(getMessageParam().get("PHONENUM"))) {  
                     throw new Exception("發(fā)送短信,需要傳入PHONENUM參數(shù)");// 為了簡單起見異常也不自定義了  
                 }// 另外短信信息,以及其他各種協(xié)議參數(shù)等等都要處理  
                 System.out.println("我是短信,發(fā)送通知給" + getMessageParam().get("PHONENUM"));  
             }  
          }

          消費者:

          package com.demoFound.factoryMethod;  
          import com.demoFound.factoryMethod.factory.IMyMessageFactory;  
          import com.demoFound.factoryMethod.factory.MyMessageFactory;  
          import com.demoFound.factoryMethod.message.IMyMessage;  
          /**
          * 工廠方法模式_消費者類
          *  
          * @author popkidorc
          *  
          */
           
          public class MyFactoryMethodMain {  
             public static void main(String[] args) {  
                 IMyMessageFactory myMessageFactory = new MyMessageFactory();  
                 IMyMessage myMessage;  
                 // 對于這個消費者來說,不用知道如何生產message這個產品,耦合度降低  
                 try {  
                     // 先來一個短信通知  
                     myMessage = myMessageFactory.createMessage("SMS");  
                     myMessage.sendMesage();  
                     // 來一個oa待辦  
                     myMessage = myMessageFactory.createMessage("OA");  
                     myMessage.sendMesage();  
                     // 來一個郵件通知  
                     myMessage = myMessageFactory.createMessage("EMAIL");  
                     myMessage.sendMesage();  
                 } catch (Exception e) {  
                     e.printStackTrace();  
                 }  
             }  
          }

          三、抽象工廠模式

          定義:為創(chuàng)建一組相關或相互依賴的對象提供一個接口,而且無需指定他們的具體類。

          類型:創(chuàng)建類模式

          類圖:

          抽象工廠模式與工廠方法模式的區(qū)別

          抽象工廠模式是工廠方法模式的升級版本,他用來創(chuàng)建一組相關或者相互依賴的對象。他與工廠方法模式的區(qū)別就在于,工廠方法模式針對的是一個產品等級結構;而抽象工廠模式則是針對的多個產品等級結構。在編程中,通常一個產品結構,表現(xiàn)為一個接口或者抽象類,也就是說,工廠方法模式提供的所有產品都是衍生自同一個接口或抽象類,而抽象工廠模式所提供的產品則是衍生自不同的接口或抽象類。

          在抽象工廠模式中,有一個產品族的概念:所謂的產品族,是指位于不同產品等級結構中功能相關聯(lián)的產品組成的家族。抽象工廠模式所提供的一系列產品就組成一個產品族;而工廠方法提供的一系列產品稱為一個等級結構。我們依然拿生產汽車的例子來說明他們之間的區(qū)別。

          在上面的類圖中,兩廂車和三廂車稱為兩個不同的等級結構;而2.0排量車和2.4排量車則稱為兩個不同的產品族。再具體一點,2.0排量兩廂車和2.4排量兩廂車屬于同一個等級結構,2.0排量三廂車和2.4排量三廂車屬于另一個等級結構;而2.0排量兩廂車和2.0排量三廂車屬于同一個產品族,2.4排量兩廂車和2.4排量三廂車屬于另一個產品族。

          明白了等級結構和產品族的概念,就理解工廠方法模式和抽象工廠模式的區(qū)別了,如果工廠的產品全部屬于同一個等級結構,則屬于工廠方法模式;如果工廠的產品來自多個等級結構,則屬于抽象工廠模式。在本例中,如果一個工廠模式提供2.0排量兩廂車和2.4排量兩廂車,那么他屬于工廠方法模式;如果一個工廠模式是提供2.4排量兩廂車和2.4排量三廂車兩個產品,那么這個工廠模式就是抽象工廠模式,因為他提供的產品是分屬兩個不同的等級結構。當然,如果一個工廠提供全部四種車型的產品,因為產品分屬兩個等級結構,他當然也屬于抽象工廠模式了。

          抽象工廠模式代碼

          interface IProduct1 {  
             public void show();  
          }  
          interface IProduct2 {  
             public void show();  
          }  
          class Product1 implements IProduct1 {  
             public void show() {  
                 System.out.println("這是1型產品");  
             }  
          }  
          class Product2 implements IProduct2 {  
             public void show() {  
                 System.out.println("這是2型產品");  
             }  
          }  
          interface IFactory {  
             public IProduct1 createProduct1();  
             public IProduct2 createProduct2();  
          }  
          class Factory implements IFactory{  
             public IProduct1 createProduct1() {  
                 return new Product1();  
             }  
             public IProduct2 createProduct2() {  
                 return new Product2();  
             }  
          }  
          public class Client {  
             public static void main(String[] args){  
                 IFactory factory = new Factory();  
                 factory.createProduct1().show();  
                 factory.createProduct2().show();  
             }  
          }

          抽象工廠模式的優(yōu)點

          抽象工廠模式除了具有工廠方法模式的優(yōu)點外,最主要的優(yōu)點就是可以在類的內部對產品族進行約束。所謂的產品族,一般或多或少的都存在一定的關聯(lián),抽象工廠模式就可以在類內部對產品族的關聯(lián)關系進行定義和描述,而不必專門引入一個新的類來進行管理。

          抽象工廠模式的缺點

          產品族的擴展將是一件十分費力的事情,假如產品族中需要增加一個新的產品,則幾乎所有的工廠類都需要進行修改。所以使用抽象工廠模式時,對產品等級結構的劃分是非常重要的。

          適用場景

          當需要創(chuàng)建的對象是一系列相互關聯(lián)或相互依賴的產品族時,便可以使用抽象工廠模式。說的更明白一點,就是一個繼承體系中,如果存在著多個等級結構(即存在著多個抽象類),并且分屬各個等級結構中的實現(xiàn)類之間存在著一定的關聯(lián)或者約束,就可以使用抽象工廠模式。假如各個等級結構中的實現(xiàn)類之間不存在關聯(lián)或約束,則使用多個獨立的工廠來對產品進行創(chuàng)建,則更合適一點。

          總結

          無論是簡單工廠模式,工廠方法模式,還是抽象工廠模式,他們都屬于工廠模式,在形式和特點上也是極為相似的,他們的最終目的都是為了解耦。在使用時,我們不必去在意這個模式到底工廠方法模式還是抽象工廠模式,因為他們之間的演變常常是令人琢磨不透的。經常你會發(fā)現(xiàn),明明使用的工廠方法模式,當新需求來臨,稍加修改,加入了一個新方法后,由于類中的產品構成了不同等級結構中的產品族,它就變成抽象工廠模式了;而對于抽象工廠模式,當減少一個方法使的提供的產品不再構成產品族之后,它就演變成了工廠方法模式。

          所以,在使用工廠模式時,只需要關心降低耦合度的目的是否達到了。


          瀏覽 33
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费的操逼视频 | 无码人妻久久一区二区三区蜜桃 | 免贾观看国产女人高潮 | 91精品国产一区三一 | 啊v在线看 |