工廠模式實現(xiàn)了創(chuàng)建者和調(diào)用者的分離。
面向?qū)ο笤O(shè)計的基本原則:
- OCP(開閉原則,Open-Closed Principle):一個軟件的實體應(yīng)當(dāng)對擴(kuò)展開發(fā),對修改關(guān)閉;
- DIP(依賴倒轉(zhuǎn)原則,Dependence Inversion Principle):要針對接口編程,不要針對實現(xiàn)編程;
- LoD(迪米特法則,Law of Demeter):只與你直接的朋友通信,而避免和陌生人通信
核心本質(zhì): - 實例化對象,用工廠方法代替new操作;
- 將選擇實現(xiàn)類、創(chuàng)建對象統(tǒng)一管理和控制;從而將調(diào)用者跟我們的實現(xiàn)解耦;
簡單工廠模式
用來生產(chǎn)同一等級結(jié)構(gòu)中的任意產(chǎn)品;(對于新增的產(chǎn)品,需要修改已有代碼)
package factory.simplefactory;
public interface Car {
void run();
}
package factory.simplefactory;
public class Audi implements Car {
public void run() {
System.out.println("奧迪Run");
}
}
package factory.simplefactory;
public class Byd implements Car {
public void run() {
System.out.println("比亞迪Run");
}
}
package factory.simplefactory;
public class CarFactory {
public static Car createCar(String type){
if ("奧迪".equals(type)){
return new Audi();
}else if ("比亞迪".equals(type)){
return new Byd();
}else {
return null;
}
}
}
public class CarFactory02 {
public static Car createAudi(){
return new Audi();
}
public static Car createByd(){
return new Byd();
}
}
package factory.simplefactory;
public class Client02 {
public static void main(String[] args) {
Car c1 = CarFactory.createCar("奧迪");
Car c2 = CarFactory.createCar("比亞迪");
c1.run();
c2.run();
}
}
要點
- 簡單工廠模式也叫靜態(tài)工廠模式,就是工廠類一般是使用靜態(tài)方法,通過接收的參數(shù)的不同來返回不同的對象實例;
- 對于增加新產(chǎn)品無能為力!不修改代碼的話,是無法擴(kuò)展的;
工廠方法模式
用來生產(chǎn)同一等級結(jié)構(gòu)中的固定產(chǎn)品;(支持增加任意產(chǎn)品)
要點
- 為了避免簡單工廠模式的缺點,不完全滿足OCP;
- 工廠方法模式和簡單工廠模式最大的不同在于,簡單工廠模式只有一個(對于一個項目或者一個獨(dú)立模塊而言)工廠類,而工廠方法模式有一組實現(xiàn)了相同接口的工廠類;
package factory.factorymethod;
public interface CarFactory {
Car createCar();
}
package factory.factorymethod;
public class AudiFactory implements CarFactory{
public Car createCar() {
return new Audi();
}
}
package factory.factorymethod;
public class BydFactory implements CarFactory {
public Car createCar() {
return new Byd();
}
}
package factory.factorymethod;
public class Client {
public static void main(String[] args) {
Car c1 = new AudiFactory().createCar();
Car c2 = new BydFactory().createCar();
c1.run();
c2.run();
}
}
簡單工廠模式和工廠方法模式PK
- 結(jié)構(gòu)復(fù)雜度
從這個角度比較,顯然簡單工廠模式要占優(yōu);簡單工廠模式只需要一個工廠類,而工廠方法模式的工廠類隨著產(chǎn)品類個數(shù)增加而增加,這無疑會使類的個數(shù)越來越多,從而增加結(jié)構(gòu)的復(fù)雜程度; - 代碼復(fù)雜度
代碼復(fù)雜度和結(jié)構(gòu)復(fù)雜度是一對矛盾,既然簡單工廠模式在結(jié)構(gòu)方面相對簡潔,那么它在代碼方面肯定是比工廠方法模式復(fù)雜的了,簡單工廠類隨著產(chǎn)品的增加需要增加很多方法(或代碼),而工廠方法模式每個具體工廠類值完成單一任務(wù),代碼簡潔; - 客戶端編程難度
工廠方法模式雖然在工廠類結(jié)構(gòu)中引入了接口從而滿足了OCP,但是在客戶端編碼中需要對工廠類進(jìn)行實例化;而簡單工廠模式的工廠類是一個靜態(tài)類,在客戶端無需實例化,這無疑是吸引人的優(yōu)點; - 管理上的難度
這是個關(guān)鍵問題
我們先談擴(kuò)展,眾所周知,工廠方法模式完全滿足OCP,即它有非常良好額擴(kuò)展性;那是否就說明了簡單工廠模式就沒有擴(kuò)展性呢?答案是否定的;簡單工廠模式同樣具有良好的擴(kuò)展性---擴(kuò)展的時候僅需要修改少量的代碼(修改工廠類的代碼)就可以滿足擴(kuò)展的要求了;盡管這沒有完全滿足OCP,但我們不需要太拘泥于設(shè)計理論,要知道,sun提供的java官方工具包中也有相當(dāng)多沒有滿足OCP的例子
然后我們從維護(hù)性的角度分析下,假如某個具體產(chǎn)品類需要進(jìn)行一定的修改,很可能需要修改對應(yīng)的工廠類;當(dāng)同時需要修改多個產(chǎn)品類的時候,對工廠類的修改會變得相當(dāng)麻煩(對號入座已經(jīng)是一個問題了);反而簡單工廠沒有這些麻煩,當(dāng)多個產(chǎn)品需要修改時,簡單工廠模式仍然僅僅需要修改唯一的工廠類;
抽象工廠模式{#jump}
- 用來生產(chǎn)不同產(chǎn)品族的全部產(chǎn)品;(對于增加新的產(chǎn)品,無能為力;支持增加產(chǎn)品族)
- 抽象工廠模式是工廠方法模式的升級版本,在有多個業(yè)務(wù)品種、業(yè)務(wù)分類時,通過抽象工廠模式產(chǎn)生需要的對象時一種非常好的解決方式;
package factory.abstractfactory;
public interface Engine {
void run();
void start();
}
class LuxuryEngine implements Engine{
public void run() {
System.out.println("馬力大!");
}
public void start() {
System.out.println("啟動快,加速快!");
}
}
class LowEngine implements Engine{
public void run() {
System.out.println("馬力小!");
}
public void start() {
System.out.println("啟動慢,加速慢!");
}
}
package factory.abstractfactory;
public interface Seat {
void massage();
}
class LuxurySeat implements Seat{
public void massage() {
System.out.println("可以按摩");
}
}
class LowSeat implements Seat{
public void massage() {
System.out.println("不可以按摩");
}
}
package factory.abstractfactory;
public interface Tyre {
void revolve();
}
class LuxuryTyre implements Tyre{
public void revolve() {
System.out.println("耐磨");
}
}
class LowTyre implements Tyre{
public void revolve() {
System.out.println("不耐磨");
}
}
package factory.abstractfactory;
public interface CarFactory {
Engine createEngine();
Seat createSeat();
Tyre createTyre();
}
package factory.abstractfactory;
public class LuxuryCarFactory implements CarFactory{
public Engine createEngine() {
return new LuxuryEngine();
}
public Seat createSeat() {
return new LuxurySeat();
}
public Tyre createTyre() {
return new LuxuryTyre();
}
}
package factory.abstractfactory;
public class LowCarFactory implements CarFactory{
public Engine createEngine() {
return new LowEngine();
}
public Seat createSeat() {
return new LowSeat();
}
public Tyre createTyre() {
return new LowTyre();
}
}
package factory.abstractfactory;
public class Client {
public static void main(String[] args) {
CarFactory factory = new LuxuryCarFactory();
Engine e = factory.createEngine();
e.run();
e.start();
}
}
工廠模式要點
- 簡單工廠模式(靜態(tài)工廠模式)
雖然某種程度不符合設(shè)計原則,但實際使用最多 - 工廠方法模式
不修改已有類的前提下,通過增加新的工廠類實現(xiàn)擴(kuò)展 - 抽象工廠模式
不可以增加產(chǎn)品,可以增加產(chǎn)品族
應(yīng)用場景
- JDK中Calendar的getInstance方法
- JDBC中的Connection對象的獲取
- Hibernate中SessionFactory創(chuàng)建Session
- Spring中IOC容器創(chuàng)建管理bean對象
- XML解析時的DocumentBuilderFactory創(chuàng)建解析器對象
- 反射中Class對象的newInstance()