工廠模式是最常用的創建型模式之一,在開始工廠模式之前,我們先來看一個場景,假如要設計一個電腦類,生成的電腦對象要包含CPU,那麼可能有人會這麼設計:
class PC
{
private:
string m_CPU;
public:
PC(string nPCName)
{
if("Apple" == nPCName)
{
m_CPU = "Apple_CPU";
}
else if("Dell" == nPCName)
{
m_CPU = "Dell_CPU";
}
}
string getCPU()
{
return m_CPU;
}
};
這裏舉的例子中假設蘋果電腦用自己CPU,戴爾電腦用自己的CPU(當然也可能是第三方的CPU),然後按照下邊的方式使用
int main(int argc, char* argv[])
{
PC ApplePC("Apple");
cout << ApplePC.getCPU() << endl;
return 0;
}
可以得到輸出的CPU是蘋果的,但是這裏個問題是,假如有一天要生成HP電腦,那麼我們就必須要改PC類,在裏邊增加else if("HP" == nPCName){HP電腦初始化},這就導致了每增加一個電腦品牌,都要在PC類中做修改,這違背了設計模式中的開閉原則。
爲了解決上面的問題,我們引出標題中的簡單工廠模式,在簡單工廠模式中,我們要引入三個角色:
1、Factory(工廠角色):工廠角色是簡單工廠模式的核心,負責創建所有產品實例,返回的是抽象產品類型(見第2點)
2、Product(抽象產品角色):作爲所有產品類的父類封裝了產品類的共有方法。
3、ConcreteProduct(具體產品角色):繼承自抽象產品角色而創建的實實在在的目標,並實現了抽象產品角色中的共有方法。
有了以上三點,我們來改造下我們的代碼:
首先創建一個電腦的產品類(包括PC抽象類、PC具體類),抽象類中接口爲獲取CPU的純虛函數
//PC的抽想產品類
class PC
{
public:
virtual string getCPU() = 0;
};
//具體PC類:Apple電腦,繼承自PC抽象類
class ApplePC : public PC
{
public:
string getCPU()
{
return "AppleCPU";
}
};
//具體PC類:Dell電腦,繼承自PC抽象類
class DellPC : public PC
{
public:
string getCPU()
{
return "DellCPU";
}
};
接着來創建簡單工廠的核心部分:工廠類(要點爲返回的值爲抽象產品類,才能實現多態)
class PCFactory
{
public:
//這裏設爲靜態函數的目的是可以直接通過類名::createPC調用,不需要實例化工廠對象
//需要注意的是:返回值爲產品的抽象類(這裏爲電腦抽象類PC)
static PC* createPC(string nPCName)
{
if("Apple" == nPCName)
{
return new ApplePC;
}
else if("Dell" == nPCName)
{
return new DellPC;
}
}
};
到這裏,我們的簡單工廠模式已經設計完成,使用如下:
int main(int argc, char* argv[])
{
PC* pPC = PCFactory::createPC("Apple");
cout << pPC->getCPU() << endl;
return 0;
}
簡單工廠模式在一定程度上解決了問題, 但是細心的朋友會發現,當我們需要增加HP電腦時,就需要更改PCFactory工廠類中的方法,也就是說每次更改增加一個電腦,就要重新編譯客戶端的工廠類。
導致 這個問題的原因就是:簡單工廠模式所有的產品都由同一個工廠生產,那有沒有可能是設置一個只負責下命名的總工廠,而生產產品的工作由各個子工廠完成,答案是肯定的,這就是即將要說的工廠模式。其實這 跟企業的管理模式有異曲同工之妙,總部只負責下達命令我要生產什麼,具體生產執行則由各個工廠去完成。
現在來看看工廠模式需要的幾個要素
1、Factory(抽象工廠角色):抽象工廠角色是工廠模式的核心,聲明公共的創建方法(即指令),具體工廠要繼承抽象工廠並實現接口。
2、ConcreteFactory(具體工廠角色):繼承抽象工廠,實現創建接口創建具體的產品
3、Product(抽象產品角色):作爲所有產品類的父類封裝了產品類的共有方法。
4、ConcreteProduct(具體產品角色):繼承自抽象產品角色而創建的實實在在的目標,並實現了抽象產品角色中的共有方法。
//抽象產品(電腦)
class PC
{
public:
virtual string getCPU() = 0;
};
//具體產品(Apple電腦)
class ApplePC : public PC
{
public:
string getCPU()
{
return "AppleCPU";
}
};
//具體產品(Dell電腦)
class DellPC : public PC
{
public:
string getCPU()
{
return "DellCPU";
}
};
//抽象工廠(工廠總部)
class Factory
{
public:
virtual PC* createPC() = 0;
};
//具體工廠(Apple工廠)
class AppleFactory : public Factory
{
public:
PC* createPC()
{
return new ApplePC;
}
};
//具體工廠(Dell工廠)
class DellFactory : public Factory
{
public:
PC* createPC()
{
return new DellPC;
}
};
int main(int argc, char* argv[])
{
Factory* f = new DellFactory; //下達指令到Dell工廠(要生產Dell電腦)
PC* pPC = f->createPC(); //Dell工廠生產電腦
cout << pPC->getCPU() << endl; //使用具體的產品
return 0;
}
到這,工廠模式就結束了,但是需求會回來越多,假如我要使用電腦、手機兩個設備連成一個家庭套餐使用。那就有可能不同品牌間的手機電腦無法正常連接或者使用體驗不好。比方我們用的電腦時Apple的,但是手機是HW,那麼他們的使用體驗可能就不那麼友善了。
爲了解決這個問題,我們引出了工廠模式中的最後一種:抽象工廠
抽象工廠解決的問題屬於創建一個產品族,舉個例子就是工廠裏生產蘋果電腦、蘋果手機、蘋果手環等等,生產出來的家族產品可以很吻合的配合使用。(這裏應該把抽象工廠定義成家族工廠是不是更合適些?嘿嘿嘿...)
有了以上工廠模式的基礎,抽象工廠就很簡單了,現在工廠只生產電腦,那麼我們直接把手機產品線也放進去好了,得到的結果就是生產出來的要麼是ApplePC+iPhone,要麼是DellPC+DPhnoe(額。。自己開創品牌),擡椅子上馬:
//抽象產品(電腦)
class PC
{
public:
virtual string getCPU() = 0;
};
//具體產品(Apple電腦)
class ApplePC : public PC
{
public:
string getCPU()
{
return "AppleCPU";
}
};
//具體產品(Dell電腦)
class DellPC : public PC
{
public:
string getCPU()
{
return "DellCPU";
}
};
//抽象產品(手機)
class Phone
{
public:
virtual string call() = 0;
};
//具體產品(iPhone)
class iPhone : public Phone
{
public:
string call()
{
return "iPhone du...du...";
}
};
//具體產品(DPhone)
class DPhone : public Phone
{
public:
string call()
{
return "DPhone du...du...";
}
};
//抽象工廠(工廠總部)
class Factory
{
public:
virtual PC* createPC() = 0;
virtual Phone* createPhone() = 0;
};
//具體工廠(Apple工廠)
class AppleFactory : public Factory
{
public:
PC* createPC()
{
return new ApplePC;
}
Phone* createPhone()
{
return new iPhone;
}
};
//具體工廠(Dell工廠)
class DellFactory : public Factory
{
public:
PC* createPC()
{
return new DellPC;
}
Phone* createPhone()
{
return new DPhone;
}
};
int main(int argc, char* argv[])
{
Factory* f = new AppleFactory; //下達指令到Apple工廠(要生產Apple系列產品)
PC* pPC = f->createPC(); //Apple工廠生產Apple mac
Phone* pPhone = f->createPhone(); //Apple工廠生產iPhone
cout << pPC->getCPU() << endl; //使用Apple Mac
cout << pPhone->call() << endl;//使用iPhone
return 0;
}
到此,工廠模式的三種類型都講完了。