在詳情頁跳轉資料功能的實現
1、解決的問題
將原來分散在各個地方的物件建立過程單獨抽離出來,交給工廠類進行建立。
其他的地方想要建立物件直接找工廠(呼叫物件的方法)進行建立。
2、工廠模式的三種類型
1、簡單工廠
2、工廠方法
3、抽象工廠
3、簡單工廠
拿泡茶為例,茶葉有好多種類,比如龍井、碧螺春、毛尖等。
首先一個ITea介面:
1 public interface ITea {
2 // 沏茶
3 public void makeTea();
4 }
再定義兩種型別的茶,西湖龍井和碧螺春:
public class LongjingTea implements ITea {
@Override
public void makeTea() {
System.out.println("西湖龍井");
}
}
public class BiluochunTea implements ITea{
@Override
public void makeTea() {
System.out.println("碧螺春");
}
}
假如其它有一處程式碼要使用“茶”這個物件沏一壺茶,有如下程式碼:
1 /** 2 * 準備沏一杯茶,根據傳入的引數決定不同的茶葉型別 3 */ 4 publicITea prepareTea(String type){ 5 ITea tea = null; 6 if(type.equals("longjing")){ 7 tea = new LongjingTea(); 8 }else if(type.equals("biluochun")){ 9 tea = new BiluochunTea(); 10 } 11 if(tea != null){ 12 tea.makeTea(); 13 }14 return tea; 15 }
接下來,我們可以分析下不使用工廠模式的情況:
如果我們的工程中不是一處用了類似這段程式碼邏輯,那增加一種茶葉的型別(比如毛尖)就需要修改多處程式碼,不利於維護。
因此,可以考慮,將建立茶葉物件的邏輯抽離出來,單獨放到一個類中,這個類便是工廠類(專門生產茶葉的工廠)。這樣維護起來便方便很多,客戶端程式碼也無需知道物件建立的具體細節,只需要從工廠類中獲取物件即可。
簡單工廠類實現如下:
1 public class TeaFactory { 2 3 public ITea createTea(String type){ 4 ITea tea = null; 5 if(type.equals("longjing")){ 6 tea = new LongjingTea(); 7 }else if(type.equals("biluochun")){ 8 tea = new BiluochunTea(); 9 } 10 if(tea != null){ 11 tea.makeTea(); 12 } 13 return tea; 14 } 15 }
客戶端程式碼要使用茶物件,需要從工廠中獲取:
1 public static void main(String[] args) { 2 3 TeaFactory teaFactory = new TeaFactory(); 4 ITea tea = teaFactory.createTea("longjing"); 5 }
二、工廠方法模式
在上面的簡單工廠中,如果要建立的產品型別較多,且各個產品建立的過程不盡相同,則一個工廠類職責會變得越來越多,不符合單一職責原則。另外簡單工廠也不符合開閉原則。要新增一種產品需要修改原來的工廠類。因此,工廠方法模式中,將生產各種型別的產品的工廠也做了抽象分離。比如,上面例子中的,生產龍井的有專門的龍井工廠,生產碧螺春的有專門的碧螺春工廠。
首先建立統一的工廠介面:
1 /**
2 * 生產茶葉的統一介面
3 */
4 public interface ITeaFactory {
5
6 // 生產茶葉
7 public ITea createTea();
8 }
然後建立兩個生產不同型別產品的工廠實現類:
public class LongjingTeaFactory implements ITeaFactory{
@Override
public ITea createTea() {
return new LongjingTea();
}
}
public class BiluochunTeaFactory implements ITeaFactory{
@Override
public ITea createTea() {
return new BiluochunTea();
}
}
客戶端程式碼:
public class FactoryMethodTest {
public static void main(String[] args) {
ITeaFactory factory = new LongjingTeaFactory();
factory.createTea();
factory = new BiluochunTeaFactory();
factory.createTea();
}
}
如果要新增一種茶葉,比如毛尖,只需要新建一個生產毛尖的工廠類實現ITeaFactory即可。
可以看到符合開閉原則、單一職責原則。
工廠方法適用於以下場景:
1、建立物件需要大量重複的程式碼。
2、客戶端(應用層)不依賴於產品類例項如何被建立、實現等細節。
3、一個類通過其子類來指定建立哪個物件。
工廠方法也有缺點:
1、類的個數容易過多,增加複雜度。
2、增加了系統的抽象性和理解難度。
三、抽象工廠
舉例說明下,有兩個工廠,美的、格力。這兩個工廠都生產兩種產品:冰箱和洗衣機。
下面使用抽象工廠模式來描述每個工廠的兩種產品的建立過程。
1、首先建立兩個產品的介面類:
1 /**
2 * 冰箱
3 */
4 public interface IFridge {
6 // 冷藏
7 void coldStorage();
8 }
9
10 /**
11 * 洗衣機
12 */
13 public interface IWasher {
14 void wash();
15 }
2、建立每個工廠的兩種產品(總共四種產品):
美的的冰箱和洗衣機:
1 public class MeideFridge implements IFridge{
2 @Override
3 public void coldStorage() {
4 System.out.println("美的冰箱");
5 }
6 }
7
8 public class MeideWasher implements IWasher {
9 @Override
10 public void wash() {
11 System.out.println("美的洗衣機");
12 }
13 }
格力的冰箱和洗衣機:
1 public class GeliFridge implements IFridge {
2 @Override
3 public void coldStorage() {
4 System.out.println("格力冰箱");
5 }
6 }
7
8 public class GeliWasher implements IWasher{
9 @Override
10 public void wash() {
11 System.out.println("格力洗衣機");
12 }
13 }
3、建立抽象工廠介面
家用電器工廠,生產一組產品。
1 /**
2 * 抽象工廠介面,家用電器工廠,生產冰箱和洗衣機
3 */
4 public interface IHouseholdElectricFactory {
5
6 IFridge createFridge();
7
8 IWasher createWasher();
9 }
4、建立具體產品等級的工廠
這裡是建立美的和格力的工廠實現類。
1 public class MeideHouseholdFactory implements IHouseholdElectricFactory{ 2 @Override 3 public IFridge createFridge() { 4 return new MeideFridge(); 5 } 6 7 @Override 8 public IWasher createWasher() { 9 return new MeideWasher(); 10 } 11 } 12 13 public class GeliHouseholdFactory implements IHouseholdElectricFactory{ 14 @Override 15 public IFridge createFridge() { 16 return new GeliFridge(); 17 } 18 19 @Override 20 public IWasher createWasher() { 21 return new GeliWasher(); 22 } 23 }
5、客戶端程式碼使用
1 public class AbsFactoryTest {
2 public static void main(String[] args) {
3
4 IHouseholdElectricFactory factory = new MeideHouseholdFactory();
5 factory.createFridge().coldStorage();
6 factory.createWasher().wash();
7 }
8 }