設計模式之工廠方法模式與抽象工廠模式
前提
工廠模式,無論是簡單工廠、抽象工廠、工廠方法,都是在要建立的物件比較固定,且比較複雜,且客戶端無需關注物件建立細節的情況下,才比較適合用。
比如資料庫連線,只要只要連線所需資訊,建立連線物件的場景比較固定且比較複雜,並且客戶端(我們的應用程式碼)可以不用知道建立細節,只需給一些連線所需資訊,這種情況下,工廠模式就十分適合,給工廠配備了連線的所需資訊,然後由工廠負責建立連線,客戶端無需直到怎麼建立,只需知道用工廠get,就能獲取到連線來使用。可以避免重複程式碼。
資料庫連線池就是工廠模式很好的體現。
工廠方法模式
由於簡單工廠模式的不足,工廠方法可以比較有效彌補。
工廠方法模式是指定義一個建立物件的介面,但是讓實現這個介面的類來決定例項化哪個類。工廠方法讓類的例項化推遲到子類中進行。工廠方法模式中使用者只需要關心什麼樣的工廠實現會創建出什麼樣的物件,無需關心建立細節。
工廠方法模式主要解決產品擴充套件的問題,在簡單工廠中,隨著產品鏈的豐富,如果每個課程的建立邏輯有區別的話,工廠的職責會變得越來越多,有點像萬能工廠,並不便於維護。違反單一原則和開閉原則。
例子:
還是以pizza為例子,有ChinesePizza、USAPazza。
//pizza介面及兩個實現
public interface Pizza {
void printDesc();
}
public class USAPizza implements Pizza {
@Override
public void printDesc() {
System.out.println("美國Pizza");
}
}
public class ChinesePizza implements Pizza {
@Override
public void printDesc() {
System.out.println("中國Pizza");
}
}
//pizza工廠及兩個實現類
public interface PizzaFactory {
Pizza createPizza();
}
public class ChinesePizzaFactory implements PizzaFactory {
@Override
public Pizza createPizza() {
return new ChinesePizza();
}
}
public class USAPizzaFactory implements PizzaFactory {
@Override
public Pizza createPizza() {
return new USAPizza();
}
}
//測試
public class TestFactoryMethod {
public static void main(String[] args) {
PizzaFactory chinesePizzaFactory = new ChinesePizzaFactory();
PizzaFactory USAPizzaFactory = new USAPizzaFactory();
chinesePizzaFactory.createPizza().printDesc();
USAPizzaFactory.createPizza().printDesc();
}
}
可以看到 chinesePizzaFactory 生產chinesePizza,USAPizzaFactory 生產USAPizza,如果要新增一個產品,比如UKPizza,那麼只需建立一個UKPizza實現Pizza介面,UKPizzaFactory實現PizzaFactory介面,而不用修改工廠類,符合開閉原則和單一職責,適合產品比較多且更新比較頻繁的場景。
工廠方法適用於以下場景:
1、建立物件需要大量重複的程式碼。
2、客戶端(應用層)不依賴於產品類例項如何被建立、實現等細節。
3、一個類通過其子類來指定建立哪個物件。
工廠方法也有缺點:
1、類的個數容易過多,增加複雜度。
2、增加了系統的抽象性和理解難度。
抽象工廠
抽象工廠模式(Abastract Factory Pattern)是指提供一個建立一系列相關或相互依賴物件的介面,無須指定他們具體的類。
客戶端(應用層)不依賴於產品類例項如何被建、實現等細節,強調的是一系列相關的產品物件(屬於同一產品族)一起使用建立物件需要大量重複的程式碼。需要提供一個產品類的庫,所有的產品以同樣的接口出現,從而使客戶端不依賴於具體實現。
產品結構和產品族說明:
舉個例子:
java課程的 java視訊、java筆記、java課堂原始碼屬性同一產品族。
java課程和python課程屬性產品結構。
三個產品族介面及其實現:
public interface Video {
void videoContent();
}
public class JavaVideo implements Video {
@Override
public void videoContent() {
System.out.println("java課程視訊");
}
}
public class PythonVideo implements Video {
@Override
public void videoContent() {
System.out.println("python課程視訊");
}
}
public interface Source {
void sourceContent();
}
public class JavaSource implements Source {
@Override
public void sourceContent() {
System.out.println("java課程原始碼");
}
}
public class PythonSource implements Source {
@Override
public void sourceContent() {
System.out.println("python課程原始碼");
}
}
public interface Note {
void noteContent();
}
public class JavaNote implements Note {
@Override
public void noteContent() {
System.out.println("java課程筆記");
}
}
public class PythonNote implements Note {
@Override
public void noteContent() {
System.out.println("python課程筆記");
}
}
//抽象工廠介面及其實現:
public interface CourseFactory {
//建立一系列產品族
Note createNote();
Source createSource();
Video createVideo();
}
public class JavaCourseFactory implements CourseFactory{
//建立java課程產品族,java筆記、原始碼、視訊
@Override
public Note createNote() {
return new JavaNote();
}
@Override
public Source createSource() {
return new JavaSource();
}
@Override
public Video createVideo() {
return new JavaVideo();
}
}
public class PythonCourseFactory implements CourseFactory {
@Override
public Note createNote() {
return new PythonNote();
}
@Override
public Source createSource() {
return new PythonSource();
}
@Override
public Video createVideo() {
return new PythonVideo();
}
}
//測試
public class TestAbstractFactory {
public static void main(String[] args) {
CourseFactory courseFactory = new JavaCourseFactory();
courseFactory.createNote().noteContent();
courseFactory.createSource().sourceContent();
courseFactory.createVideo().videoContent();
}
}
適用場景:
- 適用於產品族較多並且不經常變化的情況,比如如果課程有十幾二十個產品族,如果使用工廠方法的話,會需要大量工廠類,如果使用抽象工廠,就只需一個產品等級一個工廠類。
缺點:如果新增一個產品族,需要修改所有工廠類及借款的程式碼,比如新增一個課程評價,那麼CourseFactory介面需要新增一個createScore方法,並且其所有子類都要實現修改,很明顯違背了開閉原則,所以,如果產品族不穩定的情況下,使用該模式會有一點問題。
工廠方法和抽象工廠的區別
工廠方法是針對產品等級設計的,沒有產品族的概念,比如上面的,有 video、source、note三個產品,而沒有產品族,維度不一樣。