1. 程式人生 > >工廠模式(簡單、普通、抽象)

工廠模式(簡單、普通、抽象)

概述

屬於建立型設計模式,需要生成的物件叫做產品 ,生成物件的地方叫做工廠 。

使用場景:

  1、在任何需要生成複雜物件的地方,都可以使用工廠方法模式。

  2、直接用new可以完成的不需要用工廠模式

一、簡單(靜態)工廠

 我喜歡吃粉,抽象一個粉基類(或者介面),這是產品的抽象類

package com.wbg.FactoryMode;

public abstract class Powder {
    /**
     * 描述粉
     * 桂林米粉、柳州螺螄粉
     */
    public abstract void desc();
}

來一份桂林米粉(具體的產品類)

package com.wbg.FactoryMode;

public class GlPowder extends Powder {
    @Override
    public void desc() {
        System.out.println("桂林米粉,很好吃,上海的很貴,在家才5-6塊錢");
    }
}

我老家的螺螄粉(具體的產品類)

package com.wbg.FactoryMode;

public class LsfPowder extends Powder {

    @Override
    
public void desc() { System.out.println("螺螄粉,不錯,老家6塊錢,珠海10多塊"); } }

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

package com.wbg.FactoryMode;

public class SimplePowderFactor {
    public static final int TYPE_LZ = 1;//桂林米粉
    public static final int TYPE_PM = 2;//螺螄粉
    public static Powder createNoodles(int
type) { if(type==1){ return new GlPowder(); }else { return new LsfPowder(); } } }

簡單粉店就提供二種麵條(產品),你說你要啥,他就給你啥。這裡我點了桂林米粉:

package com.wbg.FactoryMode;

/**
* 簡單工廠模式
*/
public class Customer { public static void main(String[] args) { Powder powder=SimplePowderFactor.createNoodles(SimplePowderFactor.TYPE_LZ); powder.desc(); } }

 

特點

1、 它是一個具體的類,非介面 抽象類。有一個重要的create()方法,利用if或者 switch建立產品並返回。

2、 create()方法通常是靜態的,所以也稱之為靜態工廠。

缺點

1、 擴充套件性差(我想增加一種粉,除了新增一個粉產品類,還需要修改工廠類方法)

2 、不同的產品需要不同額外引數的時候 不支援。

二、另一種簡單工廠(反射):

利用反射Class.forName(tClass.getName()).newInstance()實現的簡單工廠:

package com.wbg.FactoryMode;

public class StaticPowderFactor {
    /**
     * 傳入Class例項化粉產品類
     *
     * @param tClass
     * @param <T>
     * @return
     */
    public static <T extends Powder>T createPowder(Class<T> tClass){
        T result=null;
        try {
            result= (T) Class.forName(tClass.getName()).newInstance();
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
        return result;
    }
}

點粉:

package com.wbg.FactoryMode;

public class Customer {
    public static void main(String[] args) {
        Powder powder=StaticPowderFactor.createPowder(new LsfPowder().getClass());
        powder.desc();
    }
}

特點

1 它也是一個具體的類,非介面 抽象類。但它的create()方法,是利用反射機制生成物件返回,好處是增加一種產品時,不需要修改create()的程式碼。

缺點

1 因為Class.forName(clz.getName()).newInstance()呼叫的是無參建構函式生成物件,它和new Object()是一樣的性質,而工廠方法應該用於複雜物件的初始化 ,當需要呼叫有參的建構函式時便無能為力了,這樣像為了工廠而工廠。

2 不同的產品需要不同額外引數的時候 不支援。

三、多方法工廠

上面都有一個缺點:不同的產品需要不同額外引數的時候 不支援。

如果使用時傳遞的type、Class出錯,將不能得到正確的物件,容錯率不高。

多方法的工廠模式為不同產品,提供不同的生產方法,使用時 需要哪種產品就呼叫該種產品的方法,使用方便、容錯率高。

工廠:

package com.wbg.FactoryMode;

public class VariedPowderFactor {
    /**
     * 生產桂林米粉
     * @return
     */
    public static Powder createGl(){
        return new GlPowder();
    }
    /**
     * 生產螺絲粉
     * @return
     */
    public static Powder createLsf(){
        return new LsfPowder();
    }
}

點餐:

package com.wbg.FactoryMode;

public class Customer {
    public static void main(String[] args) {
        Powder glpowder=VariedPowderFactor.createGl();
        glpowder.desc();

        Powder lsfpowder=VariedPowderFactor.createLsf();
        lsfpowder.desc();
    }
}

 

四、普通工廠

普通工廠就是把簡單工廠中具體的工廠類,劃分成兩層:抽象工廠層+具體的工廠子類層。(一般->特殊)

工廠(抽象工廠類),作用就是生產粉:

package com.wbg.FactoryMode;

public abstract  class PowderFactory {
    public abstract Powder create();
}

 

我老家的螺螄粉(具體工廠子類):

package com.wbg.FactoryMode;

public class createLsfFactory extends PowderFactory {
    @Override
    public Powder create() {
        return new LsfPowder();
    }
}

 

 桂林米粉(具體工廠子類):

package com.wbg.FactoryMode;

public class createGlFactory extends PowderFactory{
    @Override
    public Powder create() {
        return new GlPowder();
    }
}

 使用:

package com.wbg.FactoryMode;

public class Customer {
    public static void main(String[] args) {
       PowderFactory factory=new createGlFactory();
       Powder powder=factory.create();
       powder.desc();
    }
}

 

 

普通工廠與簡單工廠模式的區別:

可以看出,普通工廠模式特點:不僅僅做出來的產品要抽象, 工廠也應該需要抽象。

工廠方法使一個產品類的例項化延遲到其具體工廠子類.

工廠方法的好處就是更擁抱變化。當需求變化,只需要增刪相應的類,不需要修改已有的類。

簡單工廠需要修改工廠類的create()方法,多方法靜態工廠模式需要增加一個靜態方法。

缺點:

引入抽象工廠層後,每次新增一個具體產品類,也要同時新增一個具體工廠類!

抽象工廠

以上介紹的工廠都是單產品系的。抽象工廠是多產品系 。

每個粉店(工廠)不僅僅賣粉,還提供飲料賣。 
提供飲料賣,飲料是產品,先抽象一個產品類,飲料:

public abstract class IDrinks {
    /**
     * 描述每種飲料多少錢
     */
    public abstract void prices();
}

可樂:

public class ColaDrinks extends IDrinks {
    @Override
    public void prices() {
        System.out.println("可樂1塊錢");
    }
}

水:

public class WaterDrinks extends IDrinks {
    @Override
    public void prices() {
        System.out.println("太辣了,我要和免費水");
    }
}

抽象粉店(抽象工廠類):

public abstract class AbstractFoodFactory {
    /**
     * 生產麵條
     *
     * @return
     */
    public abstract Powder createPowder();

    /**
     * 生產飲料
     */
    public abstract IDrinks createDrinks();
}

柳州螺螄粉(具體工廠類):

public class LsflmFoodFactory extends AbstractFoodFactory {
    @Override
    public Powder createPowder() {
        return new LsfPowder();//螺螄粉
    }

    @Override
    public IDrinks createDrinks() {
        return new WaterDrinks();//賣水
    }
}

酒店(具體工廠類):

public class hodelFoodFactory extends AbstractFoodFactory {
    @Override
    public Powder createPowder() {
        return new GlPowder();//桂林米粉很好吃,酒店都有了
    }

    @Override
    public IDrinks createDrinks() {
        return new ColaDrinks();//賣可樂
    }
}

使用:

 AbstractFoodFactory abstractFoodFactory1 = new hodelFoodFactory();
        abstractFoodFactory1.createDrinks().prices();
        abstractFoodFactory1.createPowder().desc();


        AbstractFoodFactory abstractFoodFactory2 = new LsflmFoodFactory();
        abstractFoodFactory2.createDrinks().prices();
        abstractFoodFactory2.createPowder().desc()

 

缺點

將工廠也抽象後,有個顯著問題,就是類爆炸了。而且每次拓展新產品種類,例如不僅賣吃賣喝,我還想賣其他,這需要修改抽象工廠類,因此所有的具體工廠子類,都被牽連,需要同步被修改。

demo:https://github.com/weibanggang/Factorydemo