工廠模式一般分爲簡單工廠、工廠方法和抽象工廠三種,看了很多資料,好多講的都是雲裏霧裏的。要麼是概念太多,讓人看得一臉懵逼,要麼是舉得例子不太恰當,看了更讓人迷惑了。經過自己一番研究,通過一個簡單的例子,終於搞明白了它們之間的區別。
下面以生產寶馬、奔馳汽車的工廠爲例,講解它們之間的區別。
一、簡單工廠模式
創建一個工廠類,根據傳入的參數來決定創建哪個汽車類
//汽車接口
public interface Car {
void getCar();
}
//寶馬汽車類
public class BMWCar implements Car {
@Override
public void getCar() {
System.out.println("這是寶馬車");
}
}
//奔馳汽車類
public class BenzCar implements Car {
@Override
public void getCar() {
System.out.println("這是奔馳車");
}
}
//工廠類,用於決定創建哪一個具體的汽車類
public class DefaultFactory {
public Car produce(String name){
if(name.equals("benz")){
return new BenzCar();
}else if(name.equals("bmw")){
return new BMWCar();
}
return null;
}
}
public class FTest {
public static void main(String[] args) {
DefaultFactory factory = new DefaultFactory();
Car car = factory.produce("bmw");
car.getCar(); //這是寶馬車
Car benz = factory.produce("benz");
benz.getCar(); //這是奔馳車
}
}
可以看到,在具體的工廠類DefaultFactory中,我們根據傳入的name來決定創建哪一個汽車類。當需要創建寶馬時,傳入bmw,當需要創建奔馳時傳入benz。思考一下,如果我需要創建一個大衆汽車呢。是不是需要創建一個大衆汽車類實現Car接口,還需要修改工廠類的produce方法,新增一個大衆的分支。 再回憶一下,之前講過的軟件六大設計原則之一開閉原則。很明顯,這違背了開閉原則(對修改是關閉的)。
於是,有了下邊的工廠方法,可以保證遵循開閉原則。
二、工廠方法模式
工廠方法,相比於簡單工廠,多了一個角色——工廠接口,負責定義生產汽車的公共接口,然後每個工廠實現類都去實現這個接口。
//工廠接口
public interface IFactory {
Car produce();
}
//寶馬生產工廠
public class BMWFactory implements IFactory{
@Override
public Car produce() {
return new BMWCar();
}
}
//奔馳生產工廠
public class BenzFactory implements IFactory {
@Override
public Car produce() {
return new BenzCar();
}
}
public class FacTest {
public static void main(String[] args) {
BMWFactory bmwFactory = new BMWFactory();
bmwFactory.produce().getCar(); //這是寶馬車
BenzFactory benzFactory = new BenzFactory();
benzFactory.produce().getCar(); //這是奔馳車
}
}
可以看到,我把之前的一個工廠,拆分爲兩個工廠。當具體需要哪個汽車的時候,就去實例化它對應的工廠。這樣,當再需要大衆車的時候,我只需要添加一個大衆車的類和大衆車對應的工廠實現類去實現IFactory接口就可以了。不需要修改原來的代碼,這就符合開閉原則了。
三、 抽象工廠模式
初識抽象工廠的同學,總是很迷惑它和工廠方法有什麼區別,不就是在工廠實現類裏多了幾個方法嗎。其實,抽象工廠是對工廠方法的升級,用於創建一組相互關聯或相互依賴的對象。
在此需要了解一下產品等級和產品族的關係。假如有一個汽車製造商,它只生產低配版的汽車產品(至於爲什麼,我猜是低配版更親民,銷量更高吧,哈哈),其中就包括低配寶馬和低配奔馳。還有一個汽車製造商只生產高配版的汽車(沒什麼原因,就是錢多任性,高端大氣上檔次),如高配寶馬和高配奔馳。
我們就把高配製造商或者低配製造商稱爲一個產品族。而其中的低配寶馬和低配奔馳屬於同一個產品等級,高配寶馬和高配奔馳屬於同一個產品等級。
畫一張圖來理解一下它們的概念,橫向是三個產品族,縱向是兩個產品等級。
代碼如下:
//工廠接口,包含兩個方法,創建寶馬和創建奔馳
public interface IFactory {
Car produceBMW();
Car produceBenz();
}
//-------- 高配車和工廠實現類 -------//
public class HighBMW implements Car {
@Override
public void getCar() {
System.out.println("高配寶馬車");
}
}
public class HighBenz implements Car {
@Override
public void getCar() {
System.out.println("高配奔馳車");
}
}
public class HighFactory implements IFactory {
@Override
public Car produceBMW() {
return new HighBMW();
}
@Override
public Car produceBenz() {
return new HighBenz();
}
}
//-------- 低配車和工廠實現類 ----------//
public class LowBMW implements Car {
@Override
public void getCar() {
System.out.println("低配寶馬車");
}
}
public class LowBenz implements Car {
@Override
public void getCar() {
System.out.printf("低配奔馳車");
}
}
public class LowFactory implements IFactory {
@Override
public Car produceBMW() {
return new LowBMW();
}
@Override
public Car produceBenz() {
return new LowBenz();
}
}
public class AbsTest {
public static void main(String[] args) {
HighFactory highFactory = new HighFactory();
highFactory.produceBMW().getCar(); //高配寶馬車
highFactory.produceBenz().getCar(); //高配奔馳車
LowFactory lowFactory = new LowFactory();
lowFactory.produceBMW().getCar(); //低配寶馬車
lowFactory.produceBenz().getCar(); //低配奔馳車
}
}
乍一看,抽象工廠和工廠方法特別的相似,其實這裏邊就是多了一個產品族的概念,它強調一個產品族的對象應該放到同一個工廠類裏邊。比如,我再需要一箇中配版或者豪華版的汽車製造商,只需要實現它的具體工廠類和相應的各同等級的汽車類。
總結:
- 簡單工廠顧明思議,實現比較簡單,只需要傳入一個特定參數即可,不用知道具體的工廠實現類名,缺點就是違背了開閉原則。
- 工廠方法和抽象工廠,遵守開閉原則,解耦了類關係。但是,擴展比較複雜,需要增加一系列的類。
- 需要注意,工廠方法和抽象工廠的區別就在於,抽象工廠關注於某一個產品族,當產品對象之間是有關聯關係的一個產品族時用這種方式,而工廠方法沒有產品族的概念。