1. 程式人生 > >Java設計模式學習——簡單工廠

Java設計模式學習——簡單工廠

一. 定義與型別

定義:有工程物件決定創建出哪一種產品類的例項

型別:建立型,但不屬於GOF23中設計模式

二. 適用場景

工廠類負責建立的物件比較少

客戶端(應用層)只知道傳入工廠類的引數,對於如何建立物件(邏輯)不關心

三. 優點與缺點

優點:只需要傳入一個正確的引數,就可以獲取你所需要的物件,而無需知道其建立細節

缺點:工廠類的職責相對過重,增加新的產品需要修改工廠類的判斷邏輯,違背開閉原則

四. coding

/**
 * @program: designModel
 * @description: 視訊類
 * @author: YuKai Fan
 * @create: 2018-11-13 16:46
 *
*/ public abstract class Video { public abstract void product(); }
/**
 * @program: designModel
 * @description: java視訊類
 * @author: YuKai Fan
 * @create: 2018-11-13 16:47
 **/
public class JavaVideo extends Video {
    public void product() {
        System.out.println("錄製java課程視訊");
    }
}
/**
* @program: designModel * @description: Python視訊類 * @author: YuKai Fan * @create: 2018-11-13 16:48 **/ public class PythonVideo extends Video{ public void product() { System.out.println("錄製Python課程視訊"); } }
/**
 * @program: designModel
 * @description:
 * @author: YuKai Fan
 * @create: 2018-11-13 16:48
 *
*/ public class Test { public static void main(String[] args) { /*Video video = new JavaVideo(); video.product();*/ VideoFactory videoFactory = new VideoFactory(); Video java = videoFactory.getVideo("java"); if (java == null) { return; } java.product(); } }

這樣,應用層(客戶端)只需要傳入需要的型別,就可以得到相應的型別視訊,不知道建立的細節,UML類圖為

但是,如果要新增加一個課程的話,就必須在原有的基礎上修改程式碼,這樣違背了設計原則的開閉原則

可以對上面的程式碼進行一定的改進,通過反射的方法來完成型別的選擇

/**
 * @program: designModel
 * @description:
 * @author: YuKai Fan
 * @create: 2018-11-13 16:50
 **/
public class VideoFactory {
    public Video getVideo(Class c) {
        Video video = null;
        try {
            video = (Video) Class.forName(c.getName()).newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return video;
    }

    /*public Video getVideo(String type) {

        if ("java".equalsIgnoreCase(type)) {
            return new JavaVideo();

        } else if ("python".equalsIgnoreCase(type)) {
            return new PythonVideo();

        }
        return null;
    }*/
}
/**
 * @program: designModel
 * @description:
 * @author: YuKai Fan
 * @create: 2018-11-13 16:48
 **/
public class Test {
    public static void main(String[] args) {
        /*Video video = new JavaVideo();
        video.product();*/
        /*VideoFactory videoFactory = new VideoFactory();
        Video java = videoFactory.getVideo("java");
        if (java == null) {
            return;
        }
        java.product();*/
        VideoFactory videoFactory = new VideoFactory();
        Video java = videoFactory.getVideo(JavaVideo.class);
        if (java == null) {
            return;
        }
        java.product();
    }
}

這樣的好處是,應用層(客戶端)直接傳入對應的視訊類class即可,不需要修改工廠類的程式碼

五. 原始碼分析 jdk原始碼解析

在jdk中使用簡單工廠的體現:

1.calender.java中的getInstance方法中的createCalender方法

private static Calendar createCalendar(TimeZone zone,
                                           Locale aLocale)
    {
        CalendarProvider provider =
            LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
                                 .getCalendarProvider();
        if (provider != null) {
            try {
                return provider.getInstance(zone, aLocale);
            } catch (IllegalArgumentException iae) {
                // fall back to the default instantiation
            }
        }

        Calendar cal = null;
        
//這裡使用的就是簡單工廠模式,switch-case判斷返回相應的國家日期型別
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; } } } if (cal == null) { // If no known calendar type is explicitly specified, // perform the traditional way to create a Calendar: // create a BuddhistCalendar for th_TH locale, // a JapaneseImperialCalendar for ja_JP_JP locale, or // a GregorianCalendar for any other locales. // NOTE: The language, country and variant strings are interned.

       //這裡使用的就是簡單工廠模式,if-else判斷返回相應的國家日期型別
if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") { cal = new BuddhistCalendar(zone, aLocale); } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja" && aLocale.getCountry() == "JP") { cal = new JapaneseImperialCalendar(zone, aLocale); } else { cal = new GregorianCalendar(zone, aLocale); } } return cal; }

這個類的UML為:

jdbc中的載入驅動,獲取連線,也是用的簡單工廠模式