設計模式-工廠模式

關注公衆號 JavaStorm 獲取更多精彩java

工廠模式定義

工廠方法(Factory Method)模式的意義是定義一個建立產品對象的工廠接口,將實際建立工做推遲到子類當中。核心工廠類再也不負責產品的建立,這樣核心類成爲一個抽象工廠角色,僅負責具體工廠子類必須實現的接口,這樣進一步抽象化的好處是使得工廠方法模式可使系統在不修改具體工廠角色的狀況下引進新的產品。spring

看下 GOF爲工廠模式的定義:數據庫

「Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.」(在基類中定義建立對象的一個接口,讓子類決定實例化哪一個類。工廠方法讓一個類的實例化延遲到子類中進行。)設計模式

工廠模式分類

  • 簡單工廠模式 (Simple Factory),又稱靜態工廠方法模式 (Static Factory Method Pattern)。
  • 工廠方法模式(Factory Method)。
  • 抽象工廠模式(Abstract Factory)。

使用場景

  1. 生產一個發送消息的 產品對象,好比經過郵件、短信、微信公衆號等產品發送消息給用戶。
  2. Spring 中 FactoryBean 的 getObject();spring 中 各類各樣的 bean。就能夠經過工廠模式建立而且實現了依賴解耦。

工廠模式的優勢

  • 解耦:把對象的建立和使用分開。
  • 下降代碼複雜度:若是某個對象的建立比較複雜,或者其過程比較多的步驟。多個地方都會使用就會產生不少重複代碼
  • 下降維護成本:建立過程有工廠統一管理,當業務發生變化,不須要去找代碼中建立對象 A 的地方組個修改,只要在工廠裏面修改便可。開閉原則。

簡單工廠模式

其實這個並不算設計模式,適合建立簡單對象,建立的對象較少。客戶端不關心對象的建立過程。微信

簡單工廠模式角色

  • 工廠角色(Factory):簡單工廠模式的核心,負責建立全部實例的內部邏輯,提供外部使用建立所須要的產品。
  • 抽象產品角色(Product):簡單工廠所建立的類型。
  • 具體產品(Concrete Product)角色:簡單工廠模式的建立目標,全部建立的對象都是充當這個角色的某個具體類的實例。

簡單工廠代碼實現

建立發送器接口,也就是產品角色ide

public interface Sender {
    
    /**
     * 發送信息
     * @param to 收件人
     * @param msg 消息
     * @return
     */
    boolean send(String to, String msg);
    
}

建立具體產品,分別是郵件發送器、短信發送器。單元測試

public class MailSender implements Sender {

    @Override
    public boolean send(String to, String msg) {
        System.out.println("MailSender:收件人:" + to + ",消息爲:" + msg);
        return true;
    }

}


public class SmsSender implements SenderService {

    @Override
    public boolean send(String to, String msg) {
        System.out.println("SmsSender:收件人:" + to + ",消息爲:" + msg);
        return true;
    }

}

建立簡單工廠測試

/**
 * 工廠類,建立實例對象。缺點當字符串輸錯則得不到對象
 * @author unique
 *
 */
public class SendFactory {
    
    public Sender getObject(String type) {
        Sender sender = null;
        switch (type) {
        case "mail":
            senderService = new MailSender();
            break;
        case "sms":
            senderService = new SmsSender();
            break;
        default:
            System.out.println("請輸入正確類型");
            break;
        }
        return sender;
    }

}

單元測試this

public class SimpleFactoryTest {
    
    public static void main(String[] args) {
        SendFactory factory = new SendFactory();
        Sender sender = factory.getObject("mail");
        sender.send("大兄弟", "你是最棒的!");
    }

}

缺點

當咱們新增產品類的時候,就須要修改工廠類中的 getObject() 方法,不符合 開放-封閉原則。設計

工廠方法模式

工廠模式中使用最多的一種。

與簡單公差個模式最大的區別就是咱們再也不提供一個統一的工廠來建立全部的產品,二十針對不一樣的產品提供不一樣的工廠。也就是每一個產品都有一個與之對應的工廠。

適用場景

  • 一個類不知道它所須要的對象的類:在工廠方法模式中,客戶端不須要知道具體產品類的類名,只須要知道所對應的工廠便可,具體的產品對象由具體工廠類建立;客戶端須要知道建立具體產品的工廠類。
  • 一個類經過其子類來指定建立哪一個對象:在工廠方法模式中,對於抽象工廠類只須要提供一個建立產品的接口,而由其子類來肯定具體要建立的對象,利用面向對象的多態性和里氏原則。
  • 建立對象的任務委託給多個工廠子類中的某一個,客戶端在使用時能夠無需關心是哪個工廠子類建立產品子類,須要時再動態指定,可將具體工廠類的類名存儲在配置文件或數據庫中。

工廠方法模式角色

  • 抽象工廠(Abstract Factory)角色:是工廠方法模式的核心,與應用程序無關。任何在模式中建立的對象的工廠類必須實現這個接口。
  • 具體工廠(Concrete Factory)角色 :這是實現抽象工廠接口的具體工廠類,包含與應用程序密切相關的邏輯,而且受到應用程序調用以建立某一種產品對象。
  • 抽象產品(AbstractProduct)角色 :工廠方法模式所建立的對象的超類型,也就是產品對象的共同父類或共同擁有的接口。
  • 具體產品(Concrete Product)角色 :這個角色實現了抽象產品角色所定義的接口。某具體產品有專門的具體工廠建立,它們之間每每一一對應

代碼示例

基於上面的簡單工廠,咱們改造下。新建一個抽象工廠角色

public interface SenderFactory {
    
    /**
     * 生成對象
     * @return
     */
    public Sender getObject();

}

增長短信、郵件工廠類,實現抽象工廠接口。

public class SendMailFactory implements SenderFactory {

    @Override
    public Sender getObject() {
        return new MailSender();
    }

}


public class SendSmsFactory implements SenderFactory {

    @Override
    public Sender getObject() {
        return new SmsSenderServiceImpl();
    }

}

測試代碼

public class Test {

    public static void main(String[] args) {
        SenderFactory senderFactory = new SendMailFactory();
        Sender sender = senderFactory.getObject();
        sender.send("大兄弟", "你是最棒的!");
    }

}

抽象工廠模式

在工廠方法模式中,其實咱們有一個潛在乎識的意識。那就是咱們生產的都是同一類產品。抽象工廠模式是工廠方法的僅一步深化,在這個模式中的工廠類不僅僅能夠建立一種產品,而是能夠建立一組產品。這個產品會依賴多個合成一個。好比咱們的電腦廠商 有因特爾和AMD 生產的主板與CPU。這個產品族有CPU跟主板。

抽象工廠模式和工廠方法模式同樣,都符合開放-封閉原則。可是不一樣的是,工廠方法模式在增長一個具體產品的時候,都要增長對應的工廠。可是抽象工廠模式只有在新增一個類型的具體產品時才須要新增工廠。也就是說,工廠方法模式的一個工廠只能建立一個具體產品。而抽象工廠模式的一個工廠能夠建立屬於一類類型的多種具體產品。工廠建立產品的個數介於簡單工廠模式和工廠方法模式之間。

適用場景

  • 和工廠方法同樣客戶端不須要知道它所建立的對象的類。
  • 須要一組對象共同完成某種功能時,而且可能存在多組對象完成不一樣功能的狀況。(同屬於同一個產品族的產品)
  • 系統結構穩定,不會頻繁的增長對象。(由於一旦增長就須要修改原有代碼,不符合開閉原則)

抽象工廠方法模式的角色與工廠方法模式一致

咱們的電腦有主板、CPU、內存…組成。這些都是產品,如今提供一個工廠,直接同時生產出 CPU與對應的主板,避免單獨去建立。也就是所謂的一套,一個系列。

好比 有因特爾工廠出品的 CPU 與 主板,AMD 工廠出品的 CPU 與主板。

代碼示例

定義CPU 與主板兩個產品

public interface CPU {
    void calculate();
}

public interface Mainboard {
    void installCPU();
}

以及產品的具體實現,好比 AMD 公司出品的、因特爾公司出品的 CPU 與主板

public class AmdCpu implements CPU {
    /**
     * CPU的針腳數
     */
    private int pins = 0;

    public AmdCpu(int pins) {
        this.pins = pins;
    }

    @Override
    public void calculate() {
        System.out.println("AMD CPU的針腳數:" + pins);
    }
}


public class IntelCPU implements CPU {
    /**
     * CPU的針腳數
     */
    private int pins = 0;

    public IntelCPU(int pins) {
        this.pins = pins;
    }

    @Override
    public void calculate() {
        System.out.println("Intel CPU的針腳數:" + pins);
    }

}

public class AmdMainboard implements Mainboard {
    /**
     * CPU插槽的孔數
     */
    private int cpuHoles = 0;

    /**
     * 構造方法,傳入CPU插槽的孔數
     *
     * @param cpuHoles
     */
    public AmdMainboard(int cpuHoles) {
        this.cpuHoles = cpuHoles;
    }

    @Override
    public void installCPU() {
        // TODO Auto-generated method stub
        System.out.println("AMD主板的CPU插槽孔數是:" + cpuHoles);
    }
}

public class IntelMainboard implements Mainboard {
    /**
     * CPU插槽的孔數
     */
    private int cpuHoles = 0;

    /**
     * 構造方法,傳入CPU插槽的孔數
     *
     * @param cpuHoles
     */
    public IntelMainboard(int cpuHoles) {
        this.cpuHoles = cpuHoles;
    }

    @Override
    public void installCPU() {
        System.out.println("Intel主板的CPU插槽孔數是:" + cpuHoles);
    }

}

接着咱們先建立一個抽象工廠角色,能生產 CPU 與主板系列產品的工廠方法定義。

public interface MainboardCPUFactory {
    /**
     * 建立CPU對象
     *
     * @return CPU對象
     */
    public CPU createCpu();

    /**
     * 建立主板對象
     *
     * @return 主板對象
     */
    public Mainboard createMainboard();
}

因特爾工廠定義

public class IntelFactory implements MainboardCPUFactory {

    @Override
    public CPU createCpu() {
        return new IntelCPU(755);
    }

    @Override
    public Mainboard createMainboard() {
        return new IntelMainboard(755);
    }

}

AMD 工廠

public class AmdFactory implements MainboardCPUFactory {

    @Override
    public CPU createCpu() {
        return new AmdCpu(938);
    }

    @Override
    public Mainboard createMainboard() {
        return new AmdMainboard(938);
    }

}

最後咱們來測試

public class AbstactFactoryTest {
    public static void main(String[] args) {
        //使用因特爾工廠生產
        MainboardCPUFactory intelFactory = new IntelFactory();
        CPU cpu = intelFactory.createCpu();
        Mainboard mainboard = intelFactory.createMainboard();

        mainboard.installCPU();
        cpu.calculate();
    }
}

打印

Intel主板的CPU插槽孔數是:755
Intel CPU的針腳數:755

關注公衆號 JavaStorm 給你更多精彩。

相關文章
相關標籤/搜索