序
書上是三個模式——簡單工廠模式、工廠模式、抽象工廠模式,一塊說。對于昨天實在沒有休息好的狀態(tài)下,看到如此混亂的景象,確實有點受不了。好在后面一遍又一遍重復,總算是理解了。但是,既然是記筆記,也是給別人看,那么我覺得拆開來說或許更加明白。
1、背景
書上用pizza來打比方,其實還是挺愛吃,但是名字太繞口,而且也不熟悉。所以還是用餃子我覺得會更加親切些——我最愛吃的。
現(xiàn)在我要開一家餃子館,供應各種口味的餃子,三鮮餡,胡蘿卜羊肉餡,西胡蝦仁餡,芹菜牛肉餡,豬肉大蔥餡,豬肉白菜餡——看來好吃的說起來都沒完沒了。
最開始的想法是,按照如下步驟建立餃子:
1)用餃子抽象類建立餃子對象實體。
2)包餃子。
3)煮餃子。
4)裝盤,配醬油和醋。
5)上桌或打包外賣。
實現(xiàn)成的代碼如下——為了不讓很多的名詞困擾,此處直接采用更加形式化的命名方法:
//產(chǎn)品類型
abstract class ProductBase
{
@Override
public String toString() {
return "productbase";
}
}
class Product1 extends ProductBase
{
@Override
public String toString() {
return "product1";
}
}
class Product2 extends ProductBase
{
@Override
public String toString() {
return "product2";
}
}
//商店
class Store
{
ProductBase product;
public void create(String product) {
if(product.equals("product1"))
this.product=new Product1();
else if(product.equals("product2"))
this.product=new Product2();
//后續(xù)的操作
//包餃子();
//煮餃子();
//裝盤,配醬油和醋();
//上桌或打包();
}
}
上面的代碼將創(chuàng)建餃子對象和對餃子的后續(xù)的加工操作,嚴重耦合,造成以下兩個比較嚴重的問題:
1)一個函數(shù)中的代碼量過大,而且隨著新類型產(chǎn)品研發(fā),這個函數(shù)將越來越大,不容易維護。
2)當餐館發(fā)明新的餃子時,就需要修改sell()方法。原來類的封裝性就遭到破壞。
2、簡單工廠模式
根據(jù)上面的問題,我們自然想到的是將創(chuàng)建產(chǎn)品對象的那部分代碼進行封裝,這樣就實現(xiàn)了工廠模式。簡單工廠模式如下:
//產(chǎn)品類型
abstract class ProductBase
{
@Override
public String toString() {
return "productbase";
}
}
class Product1 extends ProductBase
{
@Override
public String toString() {
return "product1";
}
}
class Product2 extends ProductBase
{
@Override
public String toString() {
return "product2";
}
}
class ProductFactory
{
public ProductBase create(String product)
{
if(product.equals("product1"))
return new Product1();
else if(product.equals("product2"))
return new Product2();
else return null;
}
}
//商店
class Store
{
ProductBase product;
ProductFactory productFactory;
public Store(ProductFactory productFactory)
{
this.productFactory=productFactory;
}
public void create(String product) {
/* if(product.equals("product1"))
this.product=new Product1();
else if(product.equals("product2"))
this.product=new Product2();
*/
this.productFactory.create(product);
//后續(xù)的操作
//包餃子();
//煮餃子();
//裝盤,配醬油和醋();
//上桌或打包();
}
}
“簡單工廠模式”是將對象的生成和使用進行分離,以組合的方式,當創(chuàng)建使用某一類對象的實體時(如Store類的對象),將真正創(chuàng)建對象的工廠傳入。從而獲得以下兩方面的收益:
1)工廠可以在動態(tài)運行時的時候指定。比如我現(xiàn)在不打算開餃子店了,想做包子,由于包子和餃子的后續(xù)工作都是一樣的,所以只需把制作包子的工廠傳入Store類中就行。
2)產(chǎn)品、制作、使用三者進行了有效分離。產(chǎn)品的分離已經(jīng)在前面的策略模式中說道——用抽象接口來“臨時”代替具體類,占位置,將創(chuàng)建對象實體推遲到運行時。制作即使用了簡單工廠模式,而使用即為Store類。這樣就在一定程度上,將類之間的耦合度降到很低。
3、工廠模式
相對于簡單工廠模式,工廠模式的耦合度相對來說比較大。之所以比較大,先看下面的例子。
假設餃子店生意不錯,規(guī)模逐漸增大,最后成立一個實業(yè)公司——餃子餐飲有限公司,而且設立了各個分部——華北子公司,東北子公司,華南子公司,華東子公司,中西部子公司。為了保證所有公司生產(chǎn)的餃子質量過關,公司決定控制生產(chǎn)流程。所有子公司可以根據(jù)當?shù)靥禺a(chǎn),選擇自己的餡料,但是制作工藝必須嚴格按照公司的流程,比如每個面皮必須為10g,直徑5CM的圓面片。餡料必須20g。
這樣,既增加了靈活性——子公司可以根據(jù)當?shù)靥禺a(chǎn)選擇餡料,又保證了質量——嚴格按照母公司的規(guī)程辦事。
說這么多,我想“簡單工廠模式”和“工廠模式”應用的場景大家也應該能看出來了。
1)簡單工廠模式是針對只有一個使用者的情況來說,即程序中只有一個Store類,這個Store類可以使用多用“工廠類”來為自己加工產(chǎn)品。
2)工廠模式不同,它是針對某個基類的一堆子類,在保證某些流程不改變的情況下, 允許子類有自己的行為特征。也就是說,基類規(guī)定了框架,而子類只能在框架的基礎上修補、更改。
那么看下面的代碼就比較能說明問題了:
abstract class ProductBase
{
@Override
public String toString() {
return "productbase";
}
}
class a1 extends ProductBase
{
@Override
public String toString() {
return "a1";
}
}
class a2 extends ProductBase
{
@Override
public String toString() {
return "a2";
}
}
class b1 extends ProductBase
{
@Override
public String toString() {
return "b1";
}
}
class b2 extends ProductBase
{
@Override
public String toString() {
return "b2";
}
}
//創(chuàng)建工廠基類
abstract class FactoryBase
{
public abstract ProductBase create(String type);
final public ProductBase sell(String type)
{
ProductBase productBase;
productBase=create(type);
//后續(xù)的操作
//包餃子();
//煮餃子();
//裝盤,配醬油和醋();
//上桌或打包();
return productBase;
}
}
//實現(xiàn)工廠派生類
class Factory1 extends FactoryBase
{
@Override
public ProductBase create(String type) {
ProductBase productBase=null;
if(type.equals("a1"))
productBase=new a1();
else if(type.equals("a2"))
productBase=new a2();
return productBase;
}
}
class Factory2 extends FactoryBase
{
@Override
public ProductBase create(String type) {
ProductBase productBase=null;
if(type.equals("b1"))
productBase=new b1();
else if(type.equals("b2"))
productBase=new b2();
return productBase;
}
}
如上代碼所示:
1)分別建立產(chǎn)品基類、工廠基類。由產(chǎn)品基類,根據(jù)不同地區(qū)(地區(qū)a和地區(qū)b),構建了子類產(chǎn)品。相應的,也構建了不同的子類工廠。
2)基類工廠中,sell()方法作為對外統(tǒng)一方法,控制生產(chǎn)總流程,因此生命為final方法。而create()方法則因地制宜,按照不同地區(qū)特點,生產(chǎn)特定的產(chǎn)品。
這樣,工廠方法既保證了修改的靈活性,也保證了某些必要操作不會被修改。