2、工廠模式(設(shè)計(jì)模式筆記)

工廠模式的主要作用就是實(shí)現(xiàn)了創(chuàng)建者和調(diào)用者的分離。

一、面向?qū)ο笤O(shè)計(jì)的基本原則

  • OCP(開閉原則,Open-Closed Principle):一個(gè)軟件的實(shí)體應(yīng)當(dāng)對擴(kuò)展開放,對修改關(guān)閉。
  • DIP(依賴反轉(zhuǎn)原則,Dependency Inversion Principle):要針對接口編程,不要針對實(shí)現(xiàn)編程
  • LoD(迪米特法則,Law of Demeter):只與你直接的朋友通信,而避免和陌生人通信

二、應(yīng)用場景

  • JDKCalendargetInstance方法
  • JDBCConnection對象的獲取
  • HibernateSessionFactory創(chuàng)建Session
  • SpringIOC容器創(chuàng)建管理bean對象
  • XML解析時(shí)DocumentBuilderFactory創(chuàng)建解析器對象
  • 反射中Class對象的newInstance方法

三、詳細(xì)分類

3.1 一般情況下

Car.java

package cn.itcast.day229.factory;
public interface Car {
    public void run();
}

Audi.java

package cn.itcast.day229.factory;
public class Audi implements Car {

    public void run() {
        System.out.println("奧迪汽車");
    }
}

Benz.java

package cn.itcast.day229.factory;
public class Benz implements Car {

    public void run() {
        System.out.println("奔馳汽車");
    }
}

說明:這里有一個(gè)Car接口,其有兩個(gè)實(shí)現(xiàn),一個(gè)是Audi,一個(gè)是Benz。當(dāng)我們在不使用工廠的時(shí)候要用到這兩個(gè)實(shí)現(xiàn)的時(shí)候需要這樣,如下:

Client01.java

package cn.itcast.day229.factory;
//測試在不使用工廠模式的情況下,下面這個(gè)類就是調(diào)用者
//在使用的時(shí)候我們需要知道如何實(shí)例化對象,如果更復(fù)雜的情況就是實(shí)例化很麻煩的時(shí)候
//我們在使用的時(shí)候就很不方便,而且和各個(gè)子類耦合較緊,不利于擴(kuò)展
public class Client01 {
    public static void main(String[] args) {
        Car c1 = new Audi();
        Car c2 = new Benz();
        c1.run();
        c2.run();
    }
}

說明:如上,可以看到我們必須要了解各個(gè)實(shí)現(xiàn)的具體方法,必須自己手工進(jìn)行實(shí)例化,這樣顯然比較麻煩,下面我們看使用工廠的情況。

3.2 簡單工廠模式(靜態(tài)工廠模式)

用來生產(chǎn)同一等級結(jié)構(gòu)中的任意產(chǎn)品(對于新增的產(chǎn)品,需要修改已有的代碼)
SimpleCarFactory01.java

package cn.itcast.day229.factory;
//使用簡單工廠模式,當(dāng)然在后面如何我們想要擴(kuò)展可能會(huì)需要修改一定的代碼,所以簡單工廠是有一點(diǎn)問題的
//但有時(shí)候這可以忽略(違背了開閉原則)
public class SimpleCarFactory01 {
    
    public static Car createCar(String type) {
        if ("奧迪".equals(type)) {
            return new Audi();
        } else if ("奔馳".equals(type)) {
            return new Benz();
        } else {
            return null;
        }
    }
}

Client02.java

package cn.itcast.day229.factory;
//簡單工廠情況下,此時(shí)我們就不需要和相關(guān)的實(shí)現(xiàn)關(guān)聯(lián)了
public class Client02 {
    public static void main(String[] args) {
        Car c1 = SimpleCarFactory01.createCar("奧迪");
        Car c2 = SimpleCarFactory01.createCar("奔馳");
        
        c1.run();
        c2.run();
    }
}

說明:可以看到如果我們使用了簡單工廠模式,在使用的時(shí)候無須了解各個(gè)實(shí)現(xiàn)的詳細(xì)方法,也無須了解實(shí)現(xiàn)類的具體實(shí)現(xiàn)。只需要使用工廠為我們生產(chǎn)我們需要的實(shí)例對象即可。當(dāng)然簡單工廠還有另一種實(shí)現(xiàn)方式,實(shí)質(zhì)差不多,如下:
SimpleCarFactory02.java

package cn.itcast.day229.factory;
//第二種簡單工廠模式,其實(shí)兩種都差不多
public class SimpleCarFactory02 {
    public static Car createAudi(){
        return new Audi();
    }
    
    public static Car createBenz(){
        return new Benz();
    }
}

說明:這種實(shí)現(xiàn)的本質(zhì)和之前的類似。但是簡單工廠實(shí)現(xiàn)雖然用的較多,但是當(dāng)我們要擴(kuò)展對象實(shí)現(xiàn)的時(shí)候就需要對工廠內(nèi)部代碼進(jìn)行相關(guān)的修改,所以這破壞了設(shè)計(jì)的開閉原則,當(dāng)然有時(shí)候可以忽略。

3.2 工廠方法模式

用來生產(chǎn)同一等級結(jié)構(gòu)中的固定產(chǎn)品(支持增加任意產(chǎn)品)。為了避免簡單工廠模式的缺點(diǎn),不完全滿足OCP。工廠方法模式和簡單工廠模式最大的不同在于,簡單工廠模式只有一個(gè)(對于一個(gè)項(xiàng)目或者一個(gè)獨(dú)立模塊而言)工廠類,而工廠方法模式有一組實(shí)現(xiàn)了相同接口的工廠類。但是一般情況下我們還是使用簡單工廠模式。
FactoryMethodCarFactory.java

package cn.itcast.day229.factory;
//工廠方法模式
public interface FactoryMethodCarFactory {
    public Car createCar();
}

說明:這里我們創(chuàng)建一個(gè)工廠的接口,然后為每個(gè)類的創(chuàng)建實(shí)現(xiàn)一個(gè)對應(yīng)的工廠,由各個(gè)單獨(dú)的工廠來完全各個(gè)實(shí)例。

BenzFactory.java

package cn.itcast.day229.factory;
public class BenzFactory implements FactoryMethodCarFactory {
    public Car createCar() {
        return new Benz();
    }
}

AudiFactory.java

package cn.itcast.day229.factory;
public class AudiFactory implements FactoryMethodCarFactory {
    public Car createCar() {
        return new Audi();
    }
}

Client03.java

package cn.itcast.day229.factory;
//使用工廠方法模式
public class Client03 {
    public static void main(String[] args) {
        Car c1 = new AudiFactory().createCar();
        c1.run();
    }
}

說明:可以看到我們需要相關(guān)類的實(shí)例的時(shí)候是使用各個(gè)對應(yīng)的工廠去完成的,這里將工廠進(jìn)行了區(qū)分,當(dāng)然如果我們要對實(shí)現(xiàn)進(jìn)行擴(kuò)展就不會(huì)破壞設(shè)計(jì)原則了。如下:
Byd.java

package cn.itcast.day229.factory;
//增加一個(gè)比亞迪車,此時(shí)我們不需要修改其他代碼,只需要增加一個(gè)比亞迪汽車工廠即可。
public class Byd implements Car {
    public void run() {
        System.out.println("比亞迪汽車");
    }
}

BydFactory.java

package cn.itcast.day229.factory;
public class BydFactory implements FactoryMethodCarFactory {

    @Override
    public Car createCar() {
        return new Byd();
    }
}

說明:可以看到這樣我們就進(jìn)行了擴(kuò)展,無須對原來工廠中的方法中代碼進(jìn)行修改,這當(dāng)然更好,但是維護(hù)起來卻更復(fù)雜了。

3.3 抽象工廠模式

用來生產(chǎn)不同產(chǎn)品族的全部產(chǎn)品(對于新增的產(chǎn)品,無能為力,支持增加產(chǎn)品族)。是工廠方法模式的升級版本,在有多個(gè)業(yè)務(wù)品種、業(yè)務(wù)分類時(shí),通過抽象工廠模式產(chǎn)生需要的對象是一種很好的解決方式。之前的情況是有一個(gè)接口和多個(gè)實(shí)現(xiàn),但是有一種情況是有多個(gè)接口,每個(gè)接口又有多個(gè)實(shí)現(xiàn),此時(shí)我們需要使用抽象工廠模式來解決。

例子:這里有發(fā)動(dòng)機(jī)、座椅、輪胎三個(gè)產(chǎn)品族,也就是三個(gè)接口。而每個(gè)接口下面分別有高端和低端的實(shí)現(xiàn),對于低端和高端的實(shí)現(xiàn)我們可以跟根據(jù)情況進(jìn)行組合。

Engine.java

package cn.itcast.day231.AbstractFactory;
public interface Engine {
    
    public void run();
    public void start();
}

//高端發(fā)動(dòng)機(jī)
class LuxuryEngine implements Engine{
    @Override
    public void run() {
        System.out.println("好發(fā)動(dòng)機(jī)速度快");
    }

    @Override
    public void start() {
        System.out.println("好發(fā)動(dòng)機(jī)啟動(dòng)快");
    }
}

//低端發(fā)動(dòng)機(jī)
class LowEngine implements Engine{

    @Override
    public void run() {
        System.out.println("差發(fā)動(dòng)機(jī)速度慢");
    }

    @Override
    public void start() {
        System.out.println("差發(fā)動(dòng)機(jī)啟動(dòng)慢");
    }
}

Seat.java

package cn.itcast.day231.AbstractFactory;
//座椅接口
public interface Seat {
    public void nice();
}

//高端座椅
class LuxurySeat implements Seat{

    @Override
    public void nice() {
        System.out.println("高端座椅舒適度高");
    }
}

//低端座椅
class LowSeat implements Seat{

    @Override
    public void nice() {
        System.out.println("低端座椅舒適度低");
    }
}

Tyre.java

package cn.itcast.day231.AbstractFactory;
//輪胎
public interface Tyre {
    public void revole();
}

//高端輪胎
class LuxuryTyre implements Tyre{
    @Override
    public void revole() {
        System.out.println("高端輪胎防滑性好");
    }
}

//低端輪胎
class LowTyre implements Tyre{
    @Override
    public void revole() {
        System.out.println("低端輪胎防滑性差");
    }
}

說明:上面給出了幾個(gè)產(chǎn)品族,也就是一輛汽車必須需要引擎、座椅、輪胎三類對象,我們需要工廠來創(chuàng)建一個(gè)實(shí)例對象。

LowCarFactory.java

package cn.itcast.day231.AbstractFactory;
//低端汽車工廠
public class LowCarFactory implements CarFactory {

    @Override
    public Engine createEngine() {
        return new LowEngine();
    }

    @Override
    public Seat createSeat() {
        return new LowSeat();
    }

    @Override
    public Tyre createTyre() {
        return new LowTyre();
    }
}

LuxuryCarFactory.java

package cn.itcast.day231.AbstractFactory;
//高端汽車工廠
public class LuxuryCarFactory implements CarFactory {

    @Override
    public Engine createEngine() {
        return new LuxuryEngine();
    }

    @Override
    public Seat createSeat() {
        return new LuxurySeat();
    }

    @Override
    public Tyre createTyre() {
        return new LuxuryTyre();
    }
}

說明:上面我們給處理高端汽車工廠和低端汽車工廠,當(dāng)我們要使用時(shí)直接使用各自的工廠即可。

Client.java

package cn.itcast.day231.AbstractFactory;
//測試
public class Client {
    public static void main(String[] args) {
        CarFactory factory = new LuxuryCarFactory();
        Engine engine = factory.createEngine();
        engine.run();
        engine.start();
    }
}

說明:如上,如果我們需要一輛高端汽車,那么可以使用工廠直接生產(chǎn)我們需要的高端的引擎、座椅、輪胎。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容