java設計模式–抽象工廠模式

老莫offer發表於2018-11-08

抽象工廠模式算是工廠相關模式的終極形態,如果完全理解了上一章的工廠方法模式,那麼抽象工廠模式就很好理解了。它與工廠方法唯一的區別就是工廠的介面裡是一系列創造抽象產品的方法,而不再是一個,而相應的,抽象產品也不再是一個了,而是一系列相關的產品。這其實是工廠方法模式的一種擴充套件。
通常用繼承和組合兩種方式擴充套件一個介面或者類,一般我們推薦使用組合擴充套件一個現有的類或介面,但這並非絕對,如果你擴充套件的子類或子介面與現有的類或介面明顯是“是一個(is a)”的關係,也就是繼承的關係,那麼使用繼承可以獲得更多的好處。
定義:為建立一組相關或相互依賴的物件提供一個介面,而且無需指定他們的具體類。
抽象工廠模式的類圖:
圖片描述
首先要建立一個介面,這個介面就是指的Creator,而一組相關或者相互依賴的物件,就是指的ProductA和ProductB以及它們具體的實現類,我們返回的介面或者抽象類則是指的ProductA和ProductB介面。
java程式碼結構:
工廠類:

package net;

public interface Creator {

    ProductA createProductA();

    ProductB createProductB();

}

兩個具體的工廠實現類:

package net;

public class ConcreteCreator1 implements Creator{

    public ProductA createProductA() {
        return new ProductA1();
    }

    public ProductB createProductB() {
        return new ProductB1();
    }

}
package net;

public class ConcreteCreator2 implements Creator{

    public ProductA createProductA() {
        return new ProductA2();
    }

    public ProductB createProductB() {
        return new ProductB2();
    }

}

然後由下向上是產品類和具體的產品實現類:

package net;

interface ProductA {

    void methodA();
}

interface ProductB {

    void methodB();
}

class ProductA1 implements ProductA{

    public void methodA() {
        System.out.println("產品A系列中1型號產品的方法");
    }

}

class ProductA2 implements ProductA{

    public void methodA() {
        System.out.println("產品A系列中2型號產品的方法");
    }

}

class ProductB1 implements ProductB{

    public void methodB() {
        System.out.println("產品B系列中1型號產品的方法");
    }

}

class ProductB2 implements ProductB{

    public void methodB() {
        System.out.println("產品B系列中2型號產品的方法");
    }

}

下面是測試類:

package net;

public class Client {

    public static void main(String[] args) throws Exception {
        Creator creator = new ConcreteCreator1();
        ProductA productA = creator.createProductA();
        ProductB productB = creator.createProductB();
        productA.methodA();
        productB.methodB();

        //切換具體的工廠實現類
        creator = new ConcreteCreator2();
        productA = creator.createProductA();
        productB = creator.createProductB();
        productA.methodA();
        productB.methodB();
    }
}

測試類中我們切換了一次工廠實現類,而實際中生產的產品就有了差別。
簡單的說:不管是簡單工廠,還是工廠方法,都有一個缺陷,那就是整個模式當中只能有一個抽象產品,所以直觀的,在工廠方法模式中再新增一個創造抽象產品的方法就是抽象工廠模式了,相應的當然還有新增一個抽象產品,還有一系列具體的該抽象產品的實現。
簡單工廠模式,工廠方法模式一直到抽象工廠模式的演變過程,三者是由簡到繁的關係。他們的程式碼結構如下:
簡單工廠:

//抽象產品
interface Product{}

//具體產品
class ProductA implements Product{}
class ProductB implements Product{}

//產品工廠(下一步就是它的進化,就變成了工廠方法模式)
public class ProductFactory {

    private ProductFactory(){}

    public static Product getProduct(String productName){
        if (productName.equals("A")) {
            return new ProductA();
        }else if (productName.equals("B")) {
            return new ProductB();
        }else {
            return null;
        }
    }
}

工廠模式(簡單工廠有關產品的類和介面是不變的):

//抽象產品
interface Product{}

//具體產品
class ProductA implements Product{}
class ProductB implements Product{}

//將簡單工廠中的工廠給抽象成介面
interface Factory{
    Product getProduct();
}
//具體的工廠A,創造產品A
class FactoryA implements Factory{

    public Product getProduct() {
        return new ProductA();
    }

}
//具體的工廠B,創造產品B
class FactoryB implements Factory{

    public Product getProduct() {
        return new ProductB();
    }

}

產品部分並沒有變化,只是將簡單工廠中的工廠類抽象成介面,並給相應產品新增相應的工廠類,就進化成了工廠方法模式。
抽象工廠模式:

//抽象產品
interface Product{}

//具體產品
class ProductA implements Product{}
class ProductB implements Product{}

//多了一個抽象產品1
interface Product1{}

//具體產品1
class Product1A implements Product1{}
class Product1B implements Product1{}

//原有的工廠方法模式的工廠裡新增一個方法
interface Factory{
    Product getProduct();
    //新增另外一個產品族的創造方法
    Product1 getProduct1();
}
//具體的工廠A,創造產品A
class FactoryA implements Factory{

    public Product getProduct() {
        return new ProductA();
    }
    //新增相應的實現
    public Product1 getProduct1() {
        return new Product1A();
    }

}
//具體的工廠B,創造產品B
class FactoryB implements Factory{

    public Product getProduct() {
        return new ProductB();
    }
    //新增相應的實現
    public Product1 getProduct1() {
        return new Product1B();
    }

}

與工廠方法對比下就發現,多了一個產品系列叫Product1,工廠介面裡多了一個方法,叫getProduct1,所以抽象工廠模式就是工廠方法模式新增了抽象產品所演變而來的。
三者有著很大的關聯和明顯的關係,下面羅列下這三種設計模式依次進化的原因。
1,首先從簡單工廠進化到工廠方法,是因為工廠方法彌補了簡單工廠對修改開放的弊端,即簡單工廠違背了開閉原則。
2,從工廠方法進化到抽象工廠,是因為抽象工廠彌補了工廠方法只能創造一個系列的產品的弊端。

如果使用工廠模式去解決抽象工廠的場景,我們需要建立做個工廠模式對對應每一個產品系列。
不過,如果是引用第三方的jar中的工廠模式,原有的Product和Factory介面包括它們的一套實現是不可更改的,我們可以將jar包中的工廠方法模式擴充套件成抽象工廠模式來達到我們的目的:

//抽象產品
interface Product{}

//具體產品
class ProductA implements Product{}
class ProductB implements Product{}

//工廠介面
interface Factory{
    Product getProduct();
}

//具體的工廠A,創造產品A
class FactoryA implements Factory{

    public Product getProduct() {
        return new ProductA();
    }

}
//具體的工廠B,創造產品B
class FactoryB implements Factory{

    public Product getProduct() {
        return new ProductB();
    }

}

/*   假設以上是一個第三方jar包中的工廠方法模式,我們無法改動原始碼   */

//我們自己特有的產品
interface MyProduct{}

//我們自己特有的產品實現
class MyProductA implements MyProduct{}
class MyProductB implements MyProduct{}

//擴充套件原有的工廠介面
interface MyFactory extends Factory{
    MyProduct getMyProduct();
}

//我們自己特有的工廠A,擴充套件自原有的工廠A,並且實現獲得我們自己特有產品的介面方法
class MyFactoryA extends FactoryA implements MyFactory{

    public MyProduct getMyProduct() {
        return new MyProductA();
    }

}
//同A
class MyFactoryB extends FactoryB implements MyFactory{

    public MyProduct getMyProduct() {
        return new MyProductB();
    }

}

這樣我們就可以得到我們自己特有的抽象工廠和使用我們自己特有的產品了,並且我們自己的抽象工廠還兼併了第三方jar包中的產品,例如,我們可以使用MyFactoryA獲得jar包中的ProductA產品等。
這種方式的好處是我們可以完整的複用jar包中的各個類功能,缺點是繼承會導致系統的複雜性增加,耦合度相對較高。

所以我們還可以有另外一種做法,就是創造我們自己的一套獨有的工廠方法模式,這套體系與jar包中的類和介面毫無關係,我們再使用一個組合工廠將二者結合起來:

//抽象產品
interface Product{}

//具體產品
class ProductA implements Product{}
class ProductB implements Product{}

//工廠介面
interface Factory{
    Product getProduct();
}

//具體的工廠A,創造產品A
class FactoryA implements Factory{

    public Product getProduct() {
        return new ProductA();
    }

}
//具體的工廠B,創造產品B
class FactoryB implements Factory{

    public Product getProduct() {
        return new ProductB();
    }

}

/*   假設以上是一個第三方jar包中的工廠方法模式,我們無法改動原始碼   */

//我們自己特有的產品
interface MyProduct{}

//我們自己特有的產品實現
class MyProductA implements MyProduct{}
class MyProductB implements MyProduct{}

//我們自己的工廠介面
interface MyFactory{
    MyProduct getMyProduct();
}

//我們自己特有的工廠A,產生產品A
class MyFactoryA implements MyFactory{

    public MyProduct getMyProduct() {
        return new MyProductA();
    }

}

//我們自己特有的工廠B,產生產品B
class MyFactoryB implements MyFactory{

    public MyProduct getMyProduct() {
        return new MyProductB();
    }

}

/*  到這裡是我們自己的一套工廠方法模式,去創造我們自己的產品,以下我們將以上二者組合   */

//我們使用組合的方式將我們的產品系列和jar包中的產品組合起來
class AssortedFactory implements MyFactory,Factory{

    MyFactory myFactory;
    Factory factory;

    public AssortedFactory(MyFactory myFactory, Factory factory) {
        super();

相關文章