1. 程式人生 > 實用技巧 >《Head First 設計模式》:抽象工廠模式

《Head First 設計模式》:抽象工廠模式

正文

一、定義

抽象工廠模式提供一個介面,用於建立相關或依賴物件的家族,而不需要明確指定具體類。

要點:

  • 抽象工廠允許客戶使用抽象的介面來建立一組相關的產品,而不需要知道實際產品的具體產品是什麼。這樣一來,客戶就從具體的產品中被解耦。
  • 抽象工廠的任務是定義一個負責建立一組產品的介面。這個介面內的每個方法都負責建立一個產品,同時利用實現抽象工廠的子類來提供具體的做法。
  • 抽象工廠的方法經常以工廠方法的方式實現。

二、實現步驟

1、建立產品抽象類

(1)產品A抽象類

/**
 * 產品A抽象類
 */
public abstract class ProductA {
    
    String name;
    
    public String getName() {
        return name;
    }
}

(2)產品B抽象類

/**
 * 產品B抽象類
 */
public abstract class ProductB {
    
    String name;
    
    public String getName() {
        return name;
    }
}

2、建立具體的產品,並繼承產品抽象類

(1)產品A1

/**
 * 產品A1
 */
public class ConcreteProductA1 extends ProductA {
    
    public ConcreteProductA1() {
        name = "ConcreteProductA1";
    }
}

(2)產品A2

/**
 * 產品A2
 */
public class ConcreteProductA2 extends ProductA {
    
    public ConcreteProductA2() {
        name = "ConcreteProductA2";
    }
}

(3)產品B1

/**
 * 產品B1
 */
public class ConcreteProductB1 extends ProductB {
    
    public ConcreteProductB1() {
        name = "ConcreteProductB1";
    }
}

(4)產品B2

/**
 * 產品B2
 */
public class ConcreteProductB2 extends ProductB {
    
    public ConcreteProductB2() {
        name = "ConcreteProductB2";
    }
}

3、建立工廠介面,並定義建立產品的方法

也可以使用工廠抽象類,然後在建立具體工廠時繼承工廠抽象類。

/**
 * 抽象工廠介面
 */
public interface AbstractFactory {
    
    /**
     * 建立產品A
     */
    public ProductA createProductA();
    
    /**
     * 建立產品B
     */
    public ProductB createProductB();
}

4、建立具體的工廠,並實現工廠介面

(1)工廠1

/**
 * 工廠1
 */
public class ConcreteFactory1 implements AbstractFactory {

    @Override
    public ProductA createProductA() {
        return new ConcreteProductA1();
    }

    @Override
    public ProductB createProductB() {
        return new ConcreteProductB1();
    }
}

(2)工廠2

/**
 * 工廠2
 */
public class ConcreteFactory2 implements AbstractFactory {

    @Override
    public ProductA createProductA() {
        return new ConcreteProductA2();
    }

    @Override
    public ProductB createProductB() {
        return new ConcreteProductB2();
    }
}

5、使用工廠建立產品

public class Test {
    
    public static void main(String[] args) {
        // 工廠1
        AbstractFactory factory1 = new ConcreteFactory1();
        // 工廠2
        AbstractFactory factory2 = new ConcreteFactory2();
        
        // 工廠1建立產品
        ProductA productA = factory1.createProductA();
        System.out.println("工廠1建立產品A:" + productA.getName());
        ProductB productB = factory1.createProductB();
        System.out.println("工廠1建立產品B:" + productB.getName());
        // 工廠2建立產品
        productA = factory2.createProductA();
        System.out.println("工廠2建立產品A:" + productA.getName());
        productB = factory2.createProductB();
        System.out.println("工廠2建立產品B:" + productB.getName());
    }
}

三、舉個栗子

1、背景

假設你有一個披薩店,並且擁有許多加盟店。為了確保每家加盟店都能使用高質量的原料,你打算建造生產原料的工廠,並將原料運送到各家加盟店。

由於加盟店坐落在不同的區域,每個區域的原料是不一樣的。因此,必須能夠針對不同的區域提供相應的原料。

2、實現

為每個區域建造一個工廠,每個工廠負責建立相應區域的原料。

(1)建立所有原料抽象類

/**
 * 麵糰抽象類
 */
public abstract class Dough {
    
    String name;
    
    public String getName() {
        return name;
    }
}
/**
 * 醬料抽象類
 */
public abstract class Sauce {
    
    String name;
    
    public String getName() {
        return name;
    }
}
/**
 * 芝士抽象類
 */
public abstract class Cheese {
    
    String name;
    
    public String getName() {
        return name;
    }
}

(2)建立不同區域的所有原料

/**
 * 薄皮面團
 */
public class ThinCrustDough extends Dough {
    
    public ThinCrustDough() {
        name = "Thin Crust Dough";
    }
}
/**
 * 厚皮面團
 */
public class ThickCrustDough extends Dough {

    public ThickCrustDough() {
        name = "Thick Crust Dough";
    }
}
/**
 * 大蒜番茄醬
 */
public class MarinaraSauce extends Sauce {

    public MarinaraSauce() {
        name = "Marinara Sauce";
    }
}
/**
 * 番茄醬
 */
public class PlumTomatoSauce extends Sauce {

    public PlumTomatoSauce() {
        name = "Plum Tomato Sauce";
    }
}
/**
 * 帕馬森雷加諾乾酪
 */
public class ReggianoCheese extends Cheese{
    
    public ReggianoCheese() {
        name = "Reggiano Cheese";
    }
}
/**
 * 馬蘇裡拉乳酪
 */
public class MozzarellaCheese extends Cheese{

    public MozzarellaCheese() {
        name = "Mozzarella Cheese";
    }
}

(3)建立原料工廠介面

/**
 * 披薩原料工廠介面
 */
public interface PizzaIngredientFactory {
    
    /**
     * 建立麵糰
     */
    public Dough createDough();
    
    /**
     * 建立醬料
     */
    public Sauce createSauce();
    
    /**
     * 建立芝士
     */
    public Cheese createCheese();
    
    // 建立其他原料
}

(4)建立不同區域的原料工廠

/**
 * 紐約原料工廠
 */
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {

    @Override
    public Dough createDough() {
        return new ThinCrustDough();
    }

    @Override
    public Sauce createSauce() {
        return new MarinaraSauce();
    }

    @Override
    public Cheese createCheese() {
        return new ReggianoCheese();
    }
}
/**
 * 芝加哥原料工廠
 */
public class ChicagoPizzaIngredientFactory implements PizzaIngredientFactory {

    @Override
    public Dough createDough() {
        return new ThickCrustDough();
    }

    @Override
    public Sauce createSauce() {
        return new PlumTomatoSauce();
    }

    @Override
    public Cheese createCheese() {
        return new MozzarellaCheese();
    }
}

(5)使用不同區域的原料工廠建立原料

public class Test {
    
    public static void main(String[] args) {
        // 紐約原料工廠
        PizzaIngredientFactory nyFactory = new NYPizzaIngredientFactory();
        // 芝加哥原料工廠
        PizzaIngredientFactory chicagoFactory = new ChicagoPizzaIngredientFactory();
        
        // 使用紐約原料工廠建立原料
        Dough dough = nyFactory.createDough();
        Sauce sauce = nyFactory.createSauce();
        Cheese cheese = nyFactory.createCheese();
        System.out.println("New York Pizza Ingredient Factory Create:");
        System.out.println(" " + dough.getName());
        System.out.println(" " + sauce.getName());
        System.out.println(" " + cheese.getName() + "\n");
        // 使用芝加哥原料工廠建立原料
        dough = chicagoFactory.createDough();
        sauce = chicagoFactory.createSauce();
        cheese = chicagoFactory.createCheese();
        System.out.println("Chicago Pizza Ingredient Factory Create:");
        System.out.println(" " + dough.getName());
        System.out.println(" " + sauce.getName());
        System.out.println(" " + cheese.getName());
    }
}