閱讀790 返回首頁    go 阿裏雲 go 技術社區[雲棲]


創建型模式摘記

  係統的演化應當依賴於組合,而不是繼承;這就提出了將類的實例化委托給一個對象的要求,因此創建型模式將變的越來越重要。
創建型模式屬於對象創建模型。所謂對象創建模型就是說將實例化的工作委托給另一個對象來做。與之相對應的是類創建模型,這是一種通過繼承改變被實例化的類。
       創建型模式有兩個重要的特點:
1) 客戶不知道創建的具體類是什麼(除非看源代碼)
2) 隱藏了類的實例是如何被創建和放在一起的

一。抽象工廠模式
1.意圖:提供一個創建一係列相關或相互依賴對象的接口,而無需指定它們的具體的類。
2.適用場景:
1)一個係統要獨立於它的產品的創建、組合和表示時
2)一個係統要由多個產品係列中的一個來配置時
3)當你要強調一係列相關的產品對象的設計以便進行聯合使用時
4)當你提供一個產品類庫,而隻想顯示它們的接口而不是實現時

3.UML圖——結構
07cbd5dfdbdd4027a1ed513e503b1d6f.png
4.效果:
1)分離了具體的類,通過抽象接口將客戶與具體的類分離
2)易於交換產品係列
3)有利於產品的一致性
4)難以支持新種類的產品,比如我們現在有一個ProductC產品,我們需要增加類AbstractProductC,增加AbstractFactory:: CreanteProductC方法,並且兩個產品係列的實際創建者ConCreateFactory1、ConCreateFactor2都要實現該方 法。
可以通過給方法加參數的方式來指明創建的是什麼產品,這樣客戶代碼就無需改變,隻要傳遞不同的參數。AbstractFactory類隻需要提供一個CreateProduct(const string& name)方法即可。

5.代碼實現,以《深入淺出設計模式(java C#)》的動物工廠為例:
using System;
namespace AnimalWorld
{
    
// 抽象大陸工廠
    abstract class ContinentFactory
    {
        
abstract public Herbivore CreateHerbivore();
        
abstract public Carnivore CreateCarnivore();
    }
    
//非洲大陸,有角馬,獅子
    class AfricaFactory : ContinentFactory
    {
        
override public Herbivore CreateHerbivore()
        {
            
return new Wildebeest();
        }
        
override public Carnivore CreateCarnivore()
        {
            
return new Lion();
        }
    }
    
// 美洲大陸,有狼,野牛
    class AmericaFactory : ContinentFactory
    {
        
override public Herbivore CreateHerbivore()
        {
            
return new Bison();
        }
        
override public Carnivore CreateCarnivore()
        {
            
return new Wolf();
        }
    }
    
//食草動物"
    abstract class Herbivore
    {
    }
    
//肉食動物"
    abstract class Carnivore
    {
        
//獵食食草動物的方法
        abstract public void Eat( Herbivore h );
    }
    
//角馬
    class Wildebeest : Herbivore
    {
    }
    
//獅子"
    class Lion : Carnivore
    {
        
//重載獵食食草動物的方法
        override public void Eat( Herbivore h )
        {
            Console.WriteLine( 
this + " eats " + h );
        }
    }
    
//野牛
    class Bison : Herbivore
    {
    }
    
//
    class Wolf : Carnivore
    {
        
//重載獵食食草動物的方法
        override public void Eat( Herbivore h )
        {
            Console.WriteLine( 
this + " eats " + h );
        }
    }
    
//動物世界類
    class AnimalWorld
    {
        
private Herbivore herbivore;
        
private Carnivore carnivore;
        
// 創建兩種動物分類
        public AnimalWorld( ContinentFactory factory )
        {
            carnivore 
= factory.CreateCarnivore();
            herbivore 
= factory.CreateHerbivore();
        }
        
//運行食物鏈
        public void RunFoodChain()
        {
            
//肉食動物獵食食草動物
            carnivore.Eat( herbivore );
        }
    }
    
/// <summary>
    
/// 抽象工廠模式客戶應用測試
    
/// </summary>
    class GameApp
    {
        [STAThread]
        
static void Main(string[] args)
        {
            
//創造並運行非洲動物世界
            ContinentFactory africa = new AfricaFactory();
            AnimalWorld world 
= new AnimalWorld( africa );
            world.RunFoodChain();
            
//創造並運行美洲動物世界
            ContinentFactory america = new AmericaFactory();
            world 
= new AnimalWorld( america );
            world.RunFoodChain();
            Console.Read();
        }

    }
}

二。Builder模式
1.意圖:將一個複雜對象的構建與它的表示相分離,使得同樣的構建過程可以創建不同的表示(或者說產品)

2.適用場景:
1)當創建複雜對象的算法應該獨立於改對象的組成部分以及它們的裝配方式時
2)當構造過程必須允許被構造的對象有不同的表示時

3.UML圖——結構

c9bff79b4fbd48859316f43e1b61a265.png
Director接受一個Builder子類對象,完成創建過程,並通知Builder對象返回以及構造好的產品。

4.效果:
1)可以使你改變一個對象的內部表示
2)構造代碼和表示代碼分開
3)可以對構造過程進行更精細的控製

5。實現:以一個車輛建造過程為例(C#)
using System;

namespace CarShop
{
    
using System;
    
using System.Collections;
    
//指揮者,Director
    class Shop{
        
public void Construct( VehicleBuilder vehicleBuilder ){
            vehicleBuilder.BuildFrame();
            vehicleBuilder.BuildEngine();
            vehicleBuilder.BuildWheels();
            vehicleBuilder.BuildDoors();
        }
    }
    
/* "Builder 建造者",Builder
    抽象建造者具有四種方法
    裝配框架
    裝配發動機
    裝配輪子
    裝配車門
    
*/
    
abstract class VehicleBuilder
    {
        
protected Vehicle vehicle;
        
//返回建造完成的車輛
        public Vehicle Vehicle{
            
getreturn vehicle; }
        }
        
abstract public void BuildFrame();
        
abstract public void BuildEngine();
        
abstract public void BuildWheels();
        
abstract public void BuildDoors();
    }
    
//具體建造者-摩托車車間
    class MotorCycleBuilder : VehicleBuilder
    {
        
override public void BuildFrame(){
            vehicle 
= new Vehicle( "摩托車" );
            vehicle[ 
"frame" ] = "MotorCycle Frame";
        }

        
override public void BuildEngine(){
            vehicle[ 
"engine" ] = "500 cc";
        }

        
override public void BuildWheels(){
            vehicle[ 
"wheels" ] = "2";
        }

        
override public void BuildDoors(){
            vehicle[ 
"doors" ] = "0";
        }
    }
    
//具體建造者-轎車車間
    class CarBuilder : VehicleBuilder
    {
        
override public void BuildFrame(){
            vehicle 
= new Vehicle( "轎車" );
            vehicle[ 
"frame" ] = "Car Frame";
        }
        
override public void BuildEngine(){
            vehicle[ 
"engine" ] = "2500 cc";
        }
        
override public void BuildWheels(){
            vehicle[ 
"wheels" ] = "4";
        }
        
override public void BuildDoors(){
            vehicle[ 
"doors" ] = "4";
        }
    }
    
// 具體建造者-單腳滑行車車間
    class ScooterBuilder : VehicleBuilder
    {
        
override public void BuildFrame(){
            vehicle 
= new Vehicle( "單腳滑行車" );
            vehicle[ 
"frame" ] = "Scooter Frame";
        }

        
override public void BuildEngine(){
            vehicle[ 
"engine" ] = "none";
        }

        
override public void BuildWheels(){
            vehicle[ 
"wheels" ] = "2";
        }

        
override public void BuildDoors(){
            vehicle[ 
"doors" ] = "0";
        }
    }
    
//車輛產品類
    class Vehicle
    {
        
private string type;
        
private Hashtable parts = new Hashtable();
        
//築構函數,決定類型
        public Vehicle( string type ){
            
this.type = type;
        }
        
//索引
        public object thisstring key ]{
            
getreturn parts[ key ]; }
            
set{ parts[ key ] = value; }
        }
        
//顯示方法
        public void Show()
        {
            Console.WriteLine( 
"\n---------------------------");
            Console.WriteLine( 
"車輛類類型: "+ type );
            Console.WriteLine( 
" 框架 : " + parts[ "frame" ] );
            Console.WriteLine( 
" 發動機 : "+ parts[ "engine"] );
            Console.WriteLine( 
" #輪子數: "+ parts[ "wheels"] );
            Console.WriteLine( 
" #車門數 : "+ parts[ "doors" ] );
        }
    }
    
/// <summary>
    
/// 建造者模式應用測試
    
/// </summary>
     class CarShop
    {
        [STAThread]
        
static void Main(string[] args)
        {
            
// 創造車間及車輛建造者
            Shop shop = new Shop();
            VehicleBuilder b1 
= new ScooterBuilder();
            VehicleBuilder b2 
= new CarBuilder();
            VehicleBuilder b3 
= new MotorCycleBuilder();
            
// 築構並顯示車輛
            shop.Construct( b1 );
            b1.Vehicle.Show();
            shop.Construct( b2 );
            b2.Vehicle.Show();
            shop.Construct( b3 );
            b3.Vehicle.Show();
            Console.Read();

        }
    }
}


三。Factory Method模式
1.意圖:定義一個用於創建對象的接口,讓子類決定實例化具體的哪一個類。
2.適用場景:
1)當一個類不知道它所必須創建的對象的類的時候,讓子類來決定
2)當一個類希望由它的子類來決定它所創建的對象的時候

3。UML圖——結構:
638ccee7f75e4632a78bdda0a084690b.png
4.效果:
1)為子類提供回調函數
2)連接平行的類層次
3) 創建函數可以接收參數來決定創建什麼產品
4)Factory Method容易導致創建過多的Creator的子類以對應不同的產品,這個方法可以通過模板技術來解決

6.實現,手機工廠,產品可能是Nokia,也可能是Motorola
using System;
using System.Collections.Generic;
using System.Text;

namespace HandPhone
{
    
//手機接口
    interface Mobile
    {
         
void call();
    }

    
//手機工廠接口
    interface MobileFactory
    {
          Mobile createMobile();
    }

    
//Nokia
    class Nokia:Mobile
    {
        
public void call()
        {
            Console.WriteLine(
"This is a {0} phone"this.GetType().Name);
        }
    }

    
//Motorola
    class Motorola : Mobile
    {
        
public void call()
        {
            Console.WriteLine(
"This is a {0} phone"this.GetType().Name);
        }
    }

    
//Motorola工廠
    class MotorolaFactory : MobileFactory
    {
         
public Mobile createMobile()
        {
            
return new Motorola();
        }
    }

    
//Nokia工廠
    class NokiaFactroy : MobileFactory
    {
        
public Mobile createMobile()
        {
            
return new Nokia();
        }
    }

    
public class Client
    {
        
static void Main(String []args)
        {
            MobileFactory factory
=null;
            Mobile mobile
=null;

            factory
=new NokiaFactroy();
            mobile
=factory.createMobile();
            mobile.call();

            factory
=new MotorolaFactory();
            mobile
=factory.createMobile();
            mobile.call();
            
        }
    }

}

四。Prototype模式

1.意圖:通過原型實例指定創建對象的種類,並通過拷貝這些原型來創建新的對象

2.適用場景:
1)要實例化的類是在運行時刻指定的,比如動態裝載
2)為了避免創建一個與產品層次平行的工廠類層次
3)當一個類的實例隻能有幾個不同的狀態組合中的一種時,建立相應數目的原型並克隆它們可能比每次用合適的狀態手工化該類更方便一些。

3.UML圖——結構:
9767a24f6e804101a9c0ae875105f950.png


4.效果:
1)運行時動態增加或者刪除產品
2)減少子類的構造數目
3)用類動態配置應用
4)動態指定新的對象,通過改變結構或者值
5)缺陷在於每一個Prototype的子類都需要實現clone操作

5。實現,無論java還是C#都從語言層次內置了對prototype模式的支持。具體不再詳述。

五。singleton模式
1。意圖:保證一個類僅有一個實例,並提供一個訪問它的全局訪問點

2.適用場景:
1)當需要類隻有一個實例,並且客戶隻能通過一個全局點去訪問它
2)當這個唯一實例應該是通過子類化可擴展的,並且客戶應該無需更改代碼就能使用擴展的實例

3.UML圖:略

4.效果:
1)對唯一實例的受控訪問
2)縮小命名空間
3)允許對操作和表示的細化
4)允許可變數目的實例

5實現,關於singleton在java多線程環境下的實現,請見討論《當Singleton遇到multi-threading》,C#對singleton多線程環境下的能夠正確實現Double-checked模式:
public sealed class Singleton
{
    
private static volatile Singleton instance;
    
private static object syncRoot = new Object();

    
private Singleton() {}

    
public static Singleton Instance
    {
        
get 
        {
            
if (instance == null
            {
                
lock (syncRoot) 
                {
                    
if (instance == null
                        instance 
= new Singleton();
                }
            }

            
return instance;
        }
    }
}


本文僅作速查記憶用,摘記於《設計模式——可複用麵向對象軟件基礎》和《深入淺出設計模式(java C#)》兩書
文章轉自莊周夢蝶  ,原文發布時間5.17

最後更新:2017-05-17 12:01:54

  上一篇:go  貫徹TDD
  下一篇:go  oracle table-lock的5種模式