1. 程式人生 > >簡單工廠與工廠模式原理及案例分析

簡單工廠與工廠模式原理及案例分析

  工廠方法的規範性定義描述為:工廠方法模式定義了一個建立物件的介面,但由子類決定要例項化的類是哪一個。工廠方法讓類把例項化推遲到子類。

  在學習工廠方法前,我們應該先了解簡單工廠這一種偽模式。之所以稱之為偽模式,是因為嚴格意義上講這並不算是一種模式,個人感覺更像是將某一功能抽象成了一個功能函式。

  程式設計的場景為:有一個專門生產果凍的生產商,可以生產出蘋果、香蕉、橘子三種口味的果凍。如果現在該生產商被要求生產蘋果口味的果凍,用簡單工廠偽模式是如何編碼的呢?

  首先,我們需要有果凍父類,並且根據不同口味的果凍定義出各種果凍的具體子類。這一層我稱之為產品層:

  父類Jelly表現為:

public abstract class Jelly {  
  
    String name;             //果凍名稱  
    String fruitMaterial;   //果凍的材料  
    String pigment;          //染色  
  
    public void prepare(){  
        System.out.println("The jelly's name is "+name);  
        System.out.println("The jelly's fruitMaterial is "+fruitMaterial);  
        System.out.println("The jelly's pigment is "+pigment);  
    }  
  
    public void melt(){  
        System.out.println("melt the material");  
    }  
    public void put(){  
        System.out.println("put the fruit");  
    }  
    public void cold(){  
        System.out.println("cold the material");  
    }  
    public void box(){  
        System.out.println("put the jelly into boxes");  
    }  
  
    public String getName() {  
        return name;  
    }  
}

 以下是三種口味果凍的子類:

public class AppleJetty extends Jelly{  
  
    public AppleJetty() {  
        this.name = "appleJetty";  
        this.fruitMaterial = "apple";  
        this.pigment = "no";  
    }  
  
    @Override  
    public void put(){  
        System.out.println("put the apple");  
    }  
}  
  
  
public class BananaJetty extends Jelly{  
  
    public BananaJetty() {  
        this.name = "bananaJetty";  
        this.fruitMaterial = "banana";  
        this.pigment = "no";  
    }  
  
    @Override  
    public void put(){  
        System.out.println("put the banana");  
    }  
}  
  
  
public class OrangeJetty extends Jelly{  
  
    public OrangeJetty() {  
        this.name = "orangeJetty";  
        this.fruitMaterial = "orange";  
        this.pigment = "no";  
    }  
  
    @Override  
    public void put(){  
        System.out.println("put the orange");  
    }  
}

  產品層到此為止,接下來就需要工廠層來生產產品。這裡用JellyCompany類來表示

public class JellyCompany {  
  
    SimpleJettyFactory simpleJettyFactory;  
  
    public JellyCompany(SimpleJettyFactory simpleJettyFactory) {  
        this.simpleJettyFactory = simpleJettyFactory;  
    }  
  
    public Jelly orderJelly(String type){  
        Jelly jelly;  
        jelly = simpleJettyFactory.createJetty(type);  
  
        jelly.prepare();  
        jelly.melt();  
        jelly.put();  
        jelly.cold();  
        jelly.box();  
  
        return jelly;  
    }  
}
  此時JellyCompany類裡面的SimpleJettyFactory就是像抽象出來的功能函式。它的具體實現為:
public class SimpleJettyFactory {  
    public Jelly createJetty(String type){  
        Jelly jelly = null;  
  
        if(type.equals("appleJetty")){  
            jelly = new AppleJetty();  
        }else if(type.equals("orangeJetty")){  
            jelly = new OrangeJetty();  
        }else if(type.equals("bananaJetty")){  
            jelly = new BananaJetty();  
        }  
  
        return jelly;  
    }  
}

  最後就是執行類SimpleFactorySimulator:
public class SimpleFactorySimulator {  
    public static void main(String[] args){  
  
        SimpleJettyFactory simpleJettyFactory = new SimpleJettyFactory();  
        JellyCompany jellyCompany = new JellyCompany(simpleJettyFactory);  
        Jelly jelly = jellyCompany.orderJelly("appleJetty");  
        System.out.println("該公司已生產 "+jelly.getName());  
    }  
}

  輸出結果為:
The jelly's name is appleJetty  
The jelly's fruitMaterial is apple  
The jelly's pigment is no  
melt the material  
put the apple  
cold the material  
put the jelly into boxes  
該公司已生產 appleJetty
  但是與上面只是抽出功能函式的簡單工廠比較,工廠模式則更適於變化。現在如果該公司成立了一個分公司:上海分公司(這裡預設該公司的總部在北京)。但是由於地域性飲食差異,這使得兩個不同地方的公司生產的果凍流程有一些差異:北京總公司生產的果凍,其中的果肉傾向於更多更大,而上海分公司的果凍則更傾向於多放糖。如果某客戶要求生產北京的蘋果果凍和上海的橘子果凍,那麼簡單工廠很明顯已經不適應這種多變化需要。這時候我們來研究一下工廠模式:   同樣的,先列出model層,果凍父類Jelly為:
public abstract class Jelly {  
  
    String name;  
    String fruitMaterial;  
    String pigment;  
  
    public void prepare(){  
        System.out.println("The jelly's name is "+name);  
        System.out.println("The jelly's fruitMaterial is "+fruitMaterial);  
        System.out.println("The jelly's pigment is "+pigment);  
    }  
  
    public void melt(){  
        System.out.println("melt the material");  
    }  
    public void put(){  
        System.out.println("put the fruit");  
    }  
    public void cold(){  
        System.out.println("cold the material");  
    }  
    public void box(){  
        System.out.println("put the jelly into boxes");  
    }  
  
    public String getName() {  
        return name;  
    }  
  
}

  下面依次是上海分公司所能生產的三種果凍:
public class ShanghaiAppleJelly extends Jelly{  
  
    public ShanghaiAppleJelly() {  
        this.name = "ShanghaiAppleJetty";  
        this.fruitMaterial = "apple";  
        this.pigment = "no";  
    }  
  
    @Override  
    public void put(){  
        System.out.println("put the apple and lots of sugar");  
    }  
}  
  
  
public class ShanghaiBananaJelly extends Jelly{  
  
    public ShanghaiBananaJelly() {  
        this.name = "ShanghaiBananaJetty";  
        this.fruitMaterial = "banana";  
        this.pigment = "no";  
    }  
  
    @Override  
    public void put(){  
        System.out.println("put the banana and lots of sugar");  
    }  
}  
  
  
public class ShanghaiOrangeJelly extends Jelly{  
  
    public ShanghaiOrangeJelly() {  
        this.name = "ShanghaiOrangeJetty";  
        this.fruitMaterial = "orange";  
        this.pigment = "no";  
    }  
  
    @Override  
    public void put(){  
        System.out.println("put the orange and lots of sugar");  
    }  
}

  北京總公司所能生產的三種果凍:
public class BeijingAppleJelly extends Jelly {  
  
    public BeijingAppleJelly() {  
        this.name = "BeijingAppleJelly";  
        this.fruitMaterial = "apple";  
        this.pigment = "no";  
    }  
  
    @Override  
    public void put(){  
        System.out.println("put the apple and cut into large pieces");  
    }  
}  
  
  
public class BeijingBananaJelly extends Jelly{  
  
    public BeijingBananaJelly() {  
        this.name = "BeijingBananaJetty";  
        this.fruitMaterial = "banana";  
        this.pigment = "no";  
    }  
  
    @Override  
    public void put(){  
        System.out.println("put the banana and cut into large pieces");  
    }  
}  
  
  
public class BeijingOrangeJelly extends Jelly{  
  
    public BeijingOrangeJelly() {  
        this.name = "BeijingOrangeJetty";  
        this.fruitMaterial = "orange";  
        this.pigment = "no";  
    }  
  
    @Override  
    public void put(){  
        System.out.println("put the orange and cut into large pieces");  
    }  
}

  下面是工廠層:抽象父類JellyCompany
public abstract class JellyCompany {  
  
    public Jelly orderJelly(String type){  
        Jelly jelly;  
        jelly = createJelly(type);   //注意此處將例項化延遲到了實現子類  
  
        jelly.prepare();  
        jelly.melt();  
        jelly.put();  
        jelly.cold();  
        jelly.box();  
  
        return jelly;  
    }  
  
    abstract Jelly createJelly(String type);  
}

  北京總公司實現子類與上海子公司實現子類
public class BeijingJellyCompany extends JellyCompany {  
  
    Jelly createJelly(String type){  
        if(type.equals("appleJelly")){  
            return new BeijingAppleJelly();   //因為是北京公司,所以採用生產北京果凍的生成方法  
        }else if(type.equals("orangeJelly")){  
            return new BeijingOrangeJelly();  
        }else if(type.equals("bananaJelly")){  
            return new BeijingBananaJelly();  
        }else  
            return null;  
    }  
}  
  
public class ShanghaiJellyCompany extends JellyCompany {  
  
    Jelly createJelly(String type){  
        if(type.equals("appleJelly")){  
            return new ShanghaiAppleJelly();  
        }else if(type.equals("orangeJelly")){  
            return new ShanghaiOrangeJelly();  
        }else if(type.equals("bananaJelly")){  
            return new ShanghaiBananaJelly();  
        }else  
            return null;  
    }  
}

  最後是執行類JellySimulator:
public class JellySimulator {  
  
    public static void main(String[] agrs){  
        JellyCompany beijingJellyComyany = new BeijingJellyCompany();  
        JellyCompany shanghaiJellyComyany = new ShanghaiJellyCompany();  
  
        Jelly jelly = beijingJellyComyany.orderJelly("appleJelly");  
        System.out.println("BeijingJelly : "+jelly.getName());  
  
        System.out.println("==================");  
  
        jelly = shanghaiJellyComyany.orderJelly("orangeJelly");  
        System.out.println("ShanghaiJelly : "+jelly.getName());  
    }  
}

  執行結果為:
The jelly's name is BeijingAppleJelly  
The jelly's fruitMaterial is apple  
The jelly's pigment is no  
melt the material  
put the apple and cut into large pieces  
cold the material  
put the jelly into boxes  
BeijingJelly : BeijingAppleJelly  
==================  
The jelly's name is ShanghaiOrangeJetty  
The jelly's fruitMaterial is orange  
The jelly's pigment is no  
melt the material  
put the orange and lots of sugar  
cold the material  
put the jelly into boxes  
ShanghaiJelly : ShanghaiOrangeJetty

  通過上面的兩個例子大家可以比較一下簡單工廠與工廠模式的區別:簡單工廠更像是抽象出一個功能函式,而工廠模式則是抽象父類定義好一系列完整流程,而具體生產什麼樣產品的例項化交給子類去做。就變化的適應性而言,工廠模式更為優秀。