1. 程式人生 > >簡單工廠模式、工廠方法模式、反射工廠模式、抽象工廠模式

簡單工廠模式、工廠方法模式、反射工廠模式、抽象工廠模式

        工廠模式在當初學習.net時就聽說過,記得當初實習的簡歷上寫著熟悉三層架構和工廠模式,其實當初並不會,只是聽說過。直到前些時候才去瞭解工廠模式,其實工廠模式還是很常用的,參考大話設計模式和網上的若干部落格,初步整理出四種版本的,簡單工廠模式、工廠模式、改進的反射工廠模式、抽象工廠模式。
        首先先大概瞭解下實際運用背景,比如要設計一個整合平臺將停車場整合進來,而停車場有多個品牌供使用者選擇,這種情況就需要運用工廠模式。將停車場的特徵方法提取出來,每新加一種停車場時實現該方法即可,客戶端只需少許更改即可實現動態選擇產品。
        首先不使用工廠模式實現:

public class ParkA 
{
    public void GetParkInfo()
    {
        Console.WriteLine("ParkA");
    }
}
public class ParkB
{
    public void GetParkInfo()
    {
        Console.WriteLine("ParkB");
    }
}

        客戶端:

class Program
{
    static void Main(string[] args)
    {
        ParkA park = new ParkA();
        park.GetParkInfo();
        Console.ReadLine();
    }
}

        這客戶端是用ParkA,又一客戶用ParkB,把這段程式碼去掉換成ParkB交給客戶,第三個客戶用ParkA,只能再改回ParkA,第一個客戶和第三個客戶明明一樣,但也沒法直接用(因為第二個客戶時已經改成ParkB了),如此很多時侯就是在做重複勞動,而且每賣一個都要開發人員根據其品牌修改一番。
1.簡單工廠
        簡單工廠上場,面向介面程式設計,將選擇品牌的過程交給客戶,將停車場提取出介面,每個品牌都實現這個介面,然後提供一個工廠,使用者只要選擇自己的品牌即可。

public interface IPark
{
    void GetParkInfo();
}
public class ParkA : IPark
{
    public void GetParkInfo()
    {
        Console.WriteLine("ParkA");
    }
}
public class ParkB : IPark
{
    public void GetParkInfo()
    {
        Console.WriteLine("ParkB");
    }
}
public enum ParkTypeEnum
{
    ParkA,
    ParkB
}
public class ParkFactory
{
    public static IPark CreatePark(ParkTypeEnum parkType)
    {
        switch (parkType)
        {
            case ParkTypeEnum.ParkA:
                return new ParkA();
            case ParkTypeEnum.ParkB:
                return new ParkB();
            default:
                return null;
        }
    }
}

        客戶端:

class Program
{
    static void Main(string[] args)
    {
        IPark park = ParkFactorys.ParkFactory.CreatePark(ParkTypeEnum.ParkA);
        park.GetParkInfo();
        Console.ReadLine();
    }
}

        當有新品牌時只需實現介面,修改工廠即可。而對於已有的品牌則無需修改。
        這裡有個理論依據,里氏替換法則:任何接收父型別的地方,都應當能夠接收子型別,換句話說如果使用的是一個基類的話,那麼一定適用於其子類,而且程式察覺不出基類物件和子類物件的區別。
        開放封閉原則:對擴充套件是開放的,而對修改是封閉的。
        缺點:違反了開放封閉原則,對修改開放了,在增加一個新的品牌時必須相應增加工廠的switch分支。
2.工廠模式
        相對簡單工廠變化之處,就是工廠發生了變化,將工廠也抽象出來一個工廠介面,裡面只有一個方法,用來建立例項。每個品牌都有自己的工廠,各自實現工廠介面即可。

public interface IPark
{
    void GetParkInfo();
}
public class ParkA : IPark
{
    public void GetParkInfo()
    {
        Console.WriteLine("ParkA");
    }
}
public class ParkB : IPark
{
    public void GetParkInfo()
    {
        Console.WriteLine("ParkB");
    }
}
public interface IFactoryPark
{
    IPark CreatePark();
}
public class ParkFactoryA : IFactoryPark
{
    public IPark CreatePark()
    {
        return new ParkA();
    }
}
public class ParkFactoryB : IFactoryPark
{
    public IPark CreatePark()
    {
        return new ParkB();
    }
}

        客戶端:

class Program
{
    static void Main(string[] args)
    {
        IFactoryPark factory = new ParkFactoryA();
        IPark park=factory.CreatePark();
        park.GetParkInfo();
        Console.ReadLine();
    }
}

        這樣就符合了開放封閉原則,新加品牌同時新加相應的工廠,而無需修改原有的工廠。
        缺點:品牌多了之後工廠也會隨之變得很多。
3.反射工廠模式
        針對簡單工廠模式,還有一種改進,利用反射來封閉修改。修改工廠類,如下:

public class ParkFactory
{
    public static IPark CreatePark(string typeName)
    {
        #region 方法一
        //load中是程式集的名稱,也就是生成的DLL的名稱
        //CreateInstance後面的是類的完整名稱,帶名稱空間
        //IPark park = Assembly.Load("ParkFactorys").CreateInstance(typeName) as IPark;
        #endregion
        #region 方法二
        //GetType的引數需是類的完整名稱,帶名稱空間
        Type type = Type.GetType(typeName, true);
        IPark park = Activator.CreateInstance(type) as IPark;
        #endregion
        return park;
    }
}

        客戶端:

class Program
{
    static void Main(string[] args)
    {
        IPark park = ParkFactory.CreatePark("ParkFactorys.ParkA");
        park.GetParkInfo();
        Console.ReadLine();
    }
}

4.抽象工廠模式

        以上的三種的產品擴充套件都是針對同一個系列,當有多個時需要工廠裡將每個系列一個個的抽象,這時就要抽象工廠模式。
        比如如下例子,除了整合停車場,現在也要整合汽車,這時就需要在工廠接口裡增加建立汽車介面的方法,抽象工廠是對工廠模式的繼續擴充。

public interface IPark
{
    void GetParkInfo();
}
public class ParkA : IPark
{
    public void GetParkInfo()
    {
        Console.WriteLine("ParkA");
    }
}
public class ParkB : IPark
{
    public void GetParkInfo()
    {
        Console.WriteLine("ParkB");
    }
}
public interface ICar
{
    void Run();
}
public class CarA : ICar
{
    public void Run()
    {
        Console.WriteLine("CarA Run");
    }
}
public class CarB : ICar
{
    public void Run()
    {
        Console.WriteLine("CarB Run");
    }
}
public interface IFactory
{
    IPark CreatePark();
    ICar CreateCar();
}
public class ParkFactoryA : IFactory
{
    public IPark CreatePark()
    {
        return new ParkA();
    }

    public ICar CreateCar()
    {
        return new CarA();
    }
}
public class ParkFactoryB : IFactory
{
    public IPark CreatePark()
    {
        return new ParkB();
    }

    public ICar CreateCar()
    {
        return new CarB();
    }
}

        客戶端:

class Program
{
    static void Main(string[] args)
    {
        IFactory factory = new ParkFactoryA();
        IPark park=factory.CreatePark();
        park.GetParkInfo();
        ICar car = factory.CreateCar();
        car.Run();
        Console.ReadLine();
    }
}

        最後簡單的總結:
        簡單工廠:簡單實用,但違反開放封閉;
        工廠方法:開放封閉,單一產品;
        抽象工廠:開放封閉,多個產品;
        反射工廠:可以最大限度的解耦。 

        原始碼下載