設(shè)計(jì)模式(四)簡單工廠模式

當(dāng)你在程序代碼中看到new關(guān)鍵字時(shí),代表你看到了一個(gè)具體類被實(shí)例化,創(chuàng)建了一個(gè)新的實(shí)例化對象。這里用的是實(shí)現(xiàn),而不是接口。我們知道,代碼綁定具體類而非接口會導(dǎo)致代碼不易擴(kuò)展,更脆弱,更缺乏彈性。

假設(shè)有一款抽象汽車產(chǎn)品Car,派生出奔馳車(BenzCar),寶馬車(BMwCar),路虎車(LandRoverCar),如下圖:


作為司機(jī),要開其中一個(gè)品牌的車,例如奔馳,最直接的做法就是創(chuàng)建一個(gè)BenzCar對象,如下:

BenzCar benzCar = new BenzCar();
benzCar.drive();

如果司機(jī)想換成寶馬汽車開,就必須要修改代碼,如下:

BMWCar bmwCar = new BMWCar();
bmwCar.drive();

這也就意味著,任何時(shí)候司機(jī)換車輛開,必須要修改客戶端的代碼。

一種稍微好的方式是通過外部傳遞汽車的名稱,來決定創(chuàng)建哪一種汽車,并向上轉(zhuǎn)型成父類Car:

String carName = "Benz";
Car car = null;
if(carName.equals("Benz")) {
    car = new BenzCar();
} else if(carName.equals("BMW")) {
    car = new BMWCar();
} else if (carName.equals("LandRover")) {
    car = new LandRoverCar();
}

然而,我們在設(shè)計(jì)代碼的時(shí)候,總是希望改動(dòng)代碼越少越好,最好是不改。當(dāng)我們的汽車產(chǎn)品新增一款新品牌時(shí),上面的代碼就需要增加else if條件滿足新的品牌對象創(chuàng)建,這就造成我們的客戶端代碼總是需要跟著修改。

為了減少代碼的修改,我們的設(shè)計(jì)原則是把變化的部分單獨(dú)抽離出來,減少代碼的改動(dòng)。到此簡單工廠模式的模型就出來了,把一直需要變化而創(chuàng)建對象的代碼抽離成一個(gè)工廠類,并對外提供一個(gè)類似getInstance方法來獲取創(chuàng)建的對象,代碼如下:

public class SimpleFactory {

    public Car getCar(String name) {
        Car car = null;
        if(name.equals("Benz")) {
            car = new BenzCar();
        } else if(name.equals("BMW")) {
            car = new BMWCar();
        } else if (name.equals("LandRover")) {
            car = new LandRoverCar();
        }
        return car;
    }
}

于是,我們的客戶端代碼改寫如下:

public class TestMain {
    public static void main(String[] args) {
        Car car = SimpleFactory.getCar("Benz");
        car.drive();

        car = SimpleFactory.getCar("BMW");
        car.drive();
    }

}

如果未來增加了汽車品牌,也只需要修改簡單工廠類,而無須修改客戶端代碼,對上層代碼透明。

簡單工廠模式定義

簡單工廠模式的類圖如下,其實(shí)嚴(yán)格來說它并不是一個(gè)設(shè)計(jì)模式,反而像一種編程習(xí)慣。

Client : 通過組合SimpleFactory和產(chǎn)品父類Car的方式提供客戶功能。
SimpleFactory:內(nèi)部保持了一個(gè)產(chǎn)品父類的引用Car,也是通過組合的方式來實(shí)現(xiàn)具體產(chǎn)品的創(chuàng)建。
Car及其子類:一個(gè)產(chǎn)品家族,從父類派生出不同的同類產(chǎn)品。

簡單工廠模式缺點(diǎn)

簡單工廠模式并不滿足開閉原則:對擴(kuò)展開發(fā),對修改關(guān)閉。產(chǎn)品增加時(shí),仍然需要修改工廠類支持更多的同類產(chǎn)品。

簡單工廠的典型應(yīng)用

簡單工廠模式在JDK中最典型的應(yīng)用就是JDBC了??梢园殃P(guān)系型數(shù)據(jù)庫認(rèn)為是一種抽象產(chǎn)品,各廠商提供的具體關(guān)系型數(shù)據(jù)庫(MySQL,PostgreSQL,Oracle)則是具體產(chǎn)品。DriverManager是工廠類。應(yīng)用程序通過JDBC接口使用關(guān)系型數(shù)據(jù)庫時(shí),并不需要關(guān)心具體使用的是哪種數(shù)據(jù)庫,而直接使用DriverManager的靜態(tài)方法去得到該數(shù)據(jù)庫的Connection,具體是哪個(gè)數(shù)據(jù)庫由Class.forName加載數(shù)據(jù)庫驅(qū)動(dòng)類的全路徑名決定。

public class JDBC {

  private static final Logger LOG = LoggerFactory.getLogger(JDBC.class);
  public static void main(String[] args) {
    Connection conn = null;
    try {
      Class.forName("org.apache.hive.jdbc.HiveDriver");
      conn = DriverManager.getConnection("jdbc:hive2://127.0.0.1:10000/default");
      PreparedStatement ps = conn.prepareStatement("select count(*) from test.test");
      ps.execute();
    } catch (SQLException ex) {
      LOG.warn("Execute query failed", ex);
    } catch(ClassNotFoundException e) {
      LOG.warn("Load Hive driver failed", e);
    } finally {
      if(conn != null ){
        try {
          conn.close();
        } catch (SQLException e) {
          // NO-OPT
        }
      }
    }
  }
}

推薦閱讀

設(shè)計(jì)模式(一)策略模式
設(shè)計(jì)模式(二)觀察者模式
設(shè)計(jì)模式(三)裝飾器模式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容