設計模式之簡單工廠模式

0x01.定義與類型

  • 定義:由一個工廠對象決定建立出哪種產品類的實例。
  • 類型:建立型,但不屬於GOF23中設計模式。
  • 簡介:經過一個專門的工廠類來建立其餘類,這些被建立的類一般有一個共同的父類或接口。
  • uml類圖

simple-factory

  • 代碼
//產品接口
public interface IProduct {
    void produce();
}

//產品實現
public class Product implements IProduct{
    @Override
    public void produce() {
        System.out.println("產品邏輯");
    }
}

//產品工廠
public class ProductFactory {
    public static IProduct createProduct(String name) {
        Product product = null;
        if ("product".equals(name)) {
            product = new Product();
        }
        return product;
    }
}
  • 應用或測試
public class Test {
    public static void main(String[] args) {
        IProduct product = ProductFactory.createProduct("product");
        product.produce();
    }
}
  • 輸出結果
產品邏輯
  • 經過簡單工廠模式,能夠看到有三個要素html

    • 產品接口:產品接口的主要目的是定義產品的規範,全部的產品實現都必須遵循產品接口定義的規範。產品接口是調用者最爲關心的,產品接口定義的優劣直接決定了調用者代碼的穩定性。一樣,產品接口也能夠用抽象類來代替,但要注意最好不要違反里氏替換原則。
    • 產品實現:實現產品接口的具體類,決定了產品在客戶端中的具體行爲。
    • 產品工廠:靜態方法用來生產產品,與調用者直接交互用來提供產品。通常使用靜態方法提供,注意當變動發生時,這個類違反了開閉原則。

0x02.適用場景

  • 工廠類負責建立的對象比較少
  • 客戶端(應用層)只知道傳入工廠類的參數,對於如何建立對象(邏輯)不關心

0x03.簡單工廠的優缺點

  • 優勢:只須要傳入一個正確的參數,就能夠獲取你所須要的對象,而無須知道其建立細節
  • 缺點:工廠類的職責相對太重,增長新的產品,須要修改工廠類的判斷邏輯,違背開閉原則

0x04.簡單工廠的實線樣例

  • 假設IT教育課程,具備Java, Python等視頻。他們都是視頻類的子類,而有單獨的視頻工廠生產這些課程!
  • 課程基類
public abstract class Video {
    public abstract void produce();
}
  • 視頻工廠
public class VideoFactory {
    /**
     * 每次新增長產品實線會修改代碼
     * 不符合開閉原則
     * @param type
     * @return
     */
    public Video getVideo(String type) {
        if ("java".equalsIgnoreCase(type)) {
            return new JavaVideo();
        } else if ("python".equalsIgnoreCase(type)) {
            return new PythonVideo();
        } else return null;
    }

    /**
     * 反射方式實現
     * @param clazz
     * @return
     */
    public Video getVideo(Class clazz) {
        Video video = null;
        try {
            video = (Video) Class.forName(clazz.getName()).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return video;
    }
}
  • Java, Python視頻的具體實線類
public class JavaVideo extends Video {
    @Override
    public void produce() {
        System.out.println("錄製Java課程視頻");
    }
}
public class PythonVideo extends Video{
    @Override
    public void produce() {
        System.out.println("錄製Python課程");
    }
}
  • 最後的測試類,測試視頻工廠輸出的視頻
public class Test {

//    public static void main(String[] args) {
//        Video video = new JavaVideo();
//        video.produce();
//    }

    public static void main(String[] args) {
        VideoFactory videoFactory = new VideoFactory();
        Video video1 = videoFactory.getVideo("python");
        if (video1 != null) {
            video1.produce();
        }
        Video video2 = videoFactory.getVideo("java");
        if (video2 != null) {
            video2.produce();
        }
    }

   /* public static void main(String[] args) {
        VideoFactory videoFactory = new VideoFactory();
        Video video = videoFactory.getVideo(PythonVideo.class);
        if (video != null) {
            video.produce();
        }
    }*/
}
  • 輸出結果
錄製Python課程
錄製Java課程視頻

0x05.UML類圖

簡單工廠模式uml類圖

  • 如圖uml所示:直接的應用類中並無於具體實現類的耦合,這樣當新增具體實現類時是不須要修改應用層業務邏輯

0x06.源碼中的簡單工廠

  • Calendar.createCalendar():JDK時間處理類
//根據輸入參數區分的具體實現
if (aLocale.hasExtensions()) {
    String caltype = aLocale.getUnicodeLocaleType("ca");
    if (caltype != null) {
        switch (caltype) {
        case "buddhist":
        cal = new BuddhistCalendar(zone, aLocale);
            break;
        case "japanese":
            cal = new JapaneseImperialCalendar(zone, aLocale);
            break;
        case "gregory":
            cal = new GregorianCalendar(zone, aLocale);
            break;
        }
    }
}
  • jdbc的Class.forname("com.mysql.driver"):經過每一個db推出的不一樣的驅動,經過反射建立出鏈接。

0x07.相關代碼

0x08.推薦閱讀

相關文章
相關標籤/搜索