設計模式分類

首先先簡單說一下設計模式的分類設計模式可以分為三大類,分別是創建型設計模式、行為型設計模式以及結構型設計模式。

創建型的設計模式:單例模式(Singleton)構建模式(Builder)原型模式(Prototype)抽象工廠模式(Abstract Factory)工廠方法模式(Factory Method)

行為設計模式策略模式(Strategy)狀態模式(State)責任鏈模式(Chain of Responsibility)解釋器模式(Interpreter)命令模式(Command)觀察者模式(Observer)備忘錄模式(Memento)迭代器模式(Iterator)模板方法模式(Template Method)訪問者模式(Visitor)中介者模式(Mediator)

結構型設計模式:裝飾者模式(Decorator)代理模式(Proxy)組合模式(Composite)橋連接模式(Bridge)適配器模式(Adapter)蠅量模式(Flyweight)外觀模式(Facade)

  簡單工廠模式

      從設計模式的類型上來說,簡單工廠模式是屬于創建型模式,又叫做靜態工廠方法(StaticFactory Method)模式,但不屬于23GOF設計模式之一。簡單工廠模式是由一個工廠對象決定創建出哪一種產品類的實例。簡單工廠模式是工廠模式家族中最簡單實用的模式,可以理解為是不同工廠模式的一個特殊實現。 

簡單工廠模式的一般結構,如圖所示:

    簡單工廠模式存在三個組成部分,參考《Java與模式》一書,對應于三個不同的角色:

l 工廠角色

l 抽象產品角色

l 具體產品角色

   其實角色這個詞用的比較確切,能夠讓我們理解到,每個角色的不是單純地指一個類,可能是一組類所構成了這個角色。下面對三個角色進行描述:

1. 工廠角色

  工廠角色負責產品的生產工作。在簡單工廠模式中,工廠類是一個具體的實現類,在系統設計中工廠類負責實際對象的創建工作。

  工廠類(Factory)的特點是:它知道系統中都存在哪些能夠創建對象的具體類(ConcreteProduct),也知道該如何將創建的對象,以某種能夠屏蔽具體類實現細節的方式(AbstractProduct)提供給所需要的其他角色來使用該對象提供的數據和服務。

2.抽象產品角色

  抽象產品角色是具體的產品的抽象。抽象就是將產品的共性抽取出來,可以直接暴露給客戶端(需要使用具體產品的角色),對所有的客戶端來說,從工廠中直接獲取到的原始產品的外部形態都是相同的,沒有任何的差別,包括數據和服務。這也就是說,具體客戶端應該“秘密”掌握著某一個或一些具體產品的詳細資料(具體產品類型、數據和服務),然后根據具體客戶端(任何一個需要使用某種具體產品的數據和服務的實現類)需要什么樣的附加數據和服務,進行類類型轉換后,通過借助于對應的具體產品對象來完成其職責。

  抽象產品角色,在實際系統中可以定義為接口或者抽象類。

3.具體產品角色

  具體產品實現類一定是抽象產品類的實現或擴展。為了保證工廠類能夠創建對象,工廠類需要知道具體產品的創建方式,這就涉及到具體產品類所提供的構造方法,以便,可能工廠類會向客戶端提供具體創建服務所需要的數據。例如:某個產品類需要通過一個賬號才能構造其實例,所以工廠類必須根據它的創建需求,為客戶端提供一個帶賬號參數的生產方法,才能創建該具體產品類的對象。

  也就是說,工廠類依賴于具體產品實現類。同樣,客戶端類是依賴于工廠類的。

通過上述三個角色的描述,我們應該能夠了解,系統中哪些類能夠勝任上述的三個角色,并通過各類之間的關系,通過工廠模式來實現系統或者某個模塊。在實際的設計過程中,可能不存在完全與上述基本簡單工廠模式完全適應的,需要根據具體的需求來調整簡單工廠模式的應用。只要能夠實現系統的良好設計,有時候變化才能滿足需要。

下面用一個簡單的例子來說明一下,給大家加深一下印象(例子來自于網絡):

運動員.java
public interface 運動員 {       
        public void 跑();
        public void 跳();
}
足球運動員.java
public class 足球運動員 implements 運動員 {
        public void 跑(){
                //跑啊跑
        } 
        public void 跳(){
                //跳啊跳
        }
}
籃球運動員.java
public class 籃球運動員 implements 運動員 {
        public void 跑(){
                //do nothing
        }     
        public void 跳(){
                //do nothing
        }
}
體育協會.java
public class 體育協會 {   
        public static 運動員 注冊足球運動員(){
                return new 足球運動員();
        }     
        public static 運動員 注冊籃球運動員(){
                return new 籃球運動員();
        }
}

俱樂部.java
public class 俱樂部 {
        private 運動員 守門員;
        private 運動員 后衛;
        private 運動員 前鋒;
        public void test() {
                this.前鋒 = 體育協會.注冊足球運動員();
                this.后衛 = 體育協會.注冊足球運動員();
                this.守門員 = 體育協會.注冊足球運動員();
               
                守門員.跑();
                后衛.跳();
        }
}


以上就是簡單工廠模式的一個簡單實例,讀者應該想象不用接口不用工廠而把具體類暴露給客戶端的那種混亂情形吧(就好像沒了體育總局,各個俱樂部在市場上自己胡亂的尋找仔細需要的運動員),簡單工廠就解決了這種混亂。

工廠方法模式

工廠方法模式是類的創建模式,又叫虛擬構造子(Virtual Constructor)模式或者多態性工廠(Polymorphic Factory)模式。 工廠方法模式的用意是定義一個創建產品對象的工廠接口,將實際工作推遲到子類中。

工廠方法模式是簡單工廠模式的衍生,解決了許多簡單工廠模式的問題。首先完全實現開-閉 原則,實現了可擴展。其次更復雜的層次結構,可以應用于產品結果復雜的場合。工廠方法模式的對簡單工廠模式進行了抽象。有一個抽象的Factory類(可以是抽象類和接口),這個類將不在負責具體的產品生產,而是只制定一些規范,具體的生產工作由其子類去完成。在這個模式中,工廠類和產品類往往可以依次對應。即一個抽象工廠對應一個抽象產品,一個具體工廠對應一個具體產品,這個具體的工廠就負責生產對應的產品。 

工廠方法模式角色與結構

1.抽象工廠(Creator)角色:是工廠方法模式的核心,與應用程序無關。任何在模式中創建的對象的工廠類必須實現這個接口。  

2.具體工廠(Concrete Creator)角色:這是實現抽象工廠接口的具體工廠類,包含與應用程序密切相關的邏輯,并且受到應用程序調用以創建產品對象。

3.抽象產品(Product)角色:工廠方法模式所創建的對象的超類型,也就是產品對象的共同父類或共同擁有的接口。

4.具體產品(Concrete Product)角色:這個角色實現了抽象產品角色所定義的接口。某具體產品有專門的具體工廠創建,它們之間往往一一對應。

工廠方法模式的一般結構,如圖所示:

我們在不改變產品類(足球運動員類和籃球運動員類)的情況下,寫一下工廠方法模式的例子:

運動員.java
public interface 運動員 {       
        public void 跑();
        public void 跳();
}

足球運動員.java
public class 足球運動員 implements 運動員 {

        public void 跑(){
                //跑啊跑
        }
       
        public void 跳(){
                //跳啊跳
        }
}

籃球運動員.java
public class 籃球運動員 implements 運動員 {

        public void 跑(){
                //do nothing
        }
       
        public void 跳(){
                //do nothing
        }
}

體育協會.java
public interface 體育協會 {
        public 運動員 注冊();
}

足球協會.java
public class 足球協會 implements 體育協會 {
        public 運動員 注冊(){
                return new 足球運動員();
        }
}

籃球協會.java
public class 籃球協會 implements 體育協會 {
        public 運動員 注冊(){
                return new 籃球運動員();
        }
}

俱樂部.java
public class 俱樂部 {
        private 運動員 守門員;
        private 運動員 后衛;
        private 運動員 前鋒;

        public void test() {
                體育協會 中國足協 = new 足球協會();
               
                this.前鋒 = 中國足協.注冊();
                this.后衛 = 中國足協.注冊();

                守門員.跑();
                后衛.跳();
        }
}


很明顯可以看到,體育協會工廠類變成了體育協會接口,而實現此接口的分別是足球協會”“籃球協會等等具體的工廠類。
這樣做有什么好處呢?很明顯,這樣做就完全OCP了。如果需要再加入(或擴展)產品類(比如加多個乒乓球運動員)的話就不再需要修改工廠類了,而只需相應的再添加一個實現了工廠接口(體育協會接口)的具體工廠類。

抽象工廠模式

       抽象工廠模式是所有形態的工廠模式中最為抽象和最具一般性的一種形態。抽象工廠模式是指當有多個抽象角色時,使用的一種工廠模式。抽象工廠模式可以向客戶端提供一個接口,使客戶端在不必指定產品的具體的情況下,創建多個產品族中的產品對象。根據LSP原則,任何接受父類型的地方,都應當能夠接受子類型。因此,實際上系統所需要的,僅僅是類型與這些抽象產品角色相同的一些實例,而不是這些抽象產品的實例。換言之,也就是這些抽象產品的具體子類的實例。工廠類負責創建抽象產品的具體子類的實例。

      先來認識下什么是產品族: 位于不同產品等級結構中,功能相關聯的產品組成的家族。還是讓我們用一個例子來形象地說明一下吧。

圖中的BmwCarBenzCar就是兩個產品樹(產品層次結構);而如圖所示的BenzSportsCarBmwSportsCar就是一個產品族。他們都可以放到跑車家族中,因此功能有所關聯。同理BmwBussinessCarBenzSportsCar也是一個產品族。

抽象工廠模式中的有以下的四種角色:

抽象工廠(Abstract Factory)角色:擔任這個角色的是工廠方法模式的核心,它是與應用系統商業邏輯無關的。 

具體工廠(Concrete Factory)角色:這個角色直接在客戶端的調用下創建產品的實例。這個角色含有選擇合適的產品對象的邏輯,而這個邏輯是與應用系統的商業邏輯緊密相關的。

 抽象產品(Abstract Product)角色:擔任這個角色的類是工廠方法模式所創建的對象的父類,或它們共同擁有的接口。

具體產品(Concrete Product)角色:這個角色用以代表具體的產品。

 Abstract Factory模式的結構:

抽象工廠模式就相當于創建實例對象的new,由于經常要根據類生成實例對象,抽象工廠模式也是用來創建實例對象的,所以在需要新的事例對象時便可以考慮是否使用工廠模式。雖然這樣做可能多做一些工作,但會給你系統帶來更大的可擴展性和盡量少的修改量。

舉例來說:生產餐具和相應食物的工廠,有兩個車間,其中一個車間用以生產餐具,一個車間用以生產相應的食物。

當消費者消費時,只需要向相應的具體工廠請求具體餐具和具體食物便可以使用餐具消費食物。

使用UML圖表示以上的描述如下:

1抽象工廠與具體工廠

2抽象餐具與具體餐具(生產車間)

3抽象食物與具體食物

注:圖中廚房單詞寫錯了:kitchen

每個具體工廠生產出來的具體產品根據不同工廠的不同各不相同,但是客戶使用產品的方法是一致的。比如客戶在得到餐具和食物之后,兩者的搭配是正確的(使用湯匙喝牛奶,使用刀子切面包)。

在本例子中有3個具體工廠AKitchen BKitchen BKitchen,分別生產牛奶和湯匙、面包和刀、肉和叉子。牛奶、面包和肉都實現了食物接口。湯匙、刀和叉子都實現了餐具接口。

抽象工廠的接口定義如下所示;

    

 package abstractFactory;

public interface KitchenFactory{

   public Food getFood();

   public TableWare getTableWare();

}

抽象餐具的接口定義如下所示:

package abstractFactory;

public interface TableWare{

 public String getTool();

}

抽象事物的接口定義如下所示:

package abstractFactory;

public interface Food{

   public String getEatable();

}

而具體的實現也非常簡單,以AKitchen為例子

具體工廠AKitchen的定義如下所示;

package abstractFactory;

public class AKitchenimplements KitchenFactory{

   public Food getFood(){

      return new Milk();

   }

   public TableWare getTableWare(){

      return new Spoon();

   }

}

 

具體餐具(spoon)的定義如下所示:

package abstractFactory;

public class Spoonimplements TableWare{ 

   public String getTool() {

      return "spoon";

   }

}

具體食物(milk)的定義如下所示:

package abstractFactory;

public class Milkimplements Food{

   public String getEatable(){

      return "milk";

   }

}

客戶端的定義如下:

package abstractFactory;

public class Client{

   public void eat(KitchenFactory k){

      System.out.println("A person eat "+k.getFood().getEatable()

             +" with "+k.getTableWare().getTool()+"!");

   }

   public static void main(String[] args){

      Client client=new Client();

      KitchenFactory kf =new AKitchen();

      client.eat(kf);

      kf=new BKitchen();

      client.eat(kf);

      kf=new CKitchen();

      client.eat(kf);

   }

}


在以下情況下應當考慮使用抽象工廠模式

· 一個系統不應當依賴于產品類實例如何被創建、組合和表達的細節,這對于所有形態的工廠模式都是重要的。

· 這個系統有多于一個的產品族,而系統只消費其中某一產品族。

· 同屬于同一個產品族的產品是在一起使用的,這一約束必須在系統的設計中體現出來。

· 系統提供一個產品類的庫,所有的產品以同樣的接口出現,從而使客戶端不依賴于實現。



作者:csh624366188 發表于2012-4-15 9:02:40 原文鏈接
閱讀:119 評論:2 查看評論