工廠類模式(一)簡單工廠

工廠模式為創(chuàng)建對象提供了接口甩骏,把對象的創(chuàng)建交給工廠來處理,而不是我們主動的去new。一方面可以屏蔽對象創(chuàng)建的邏輯根蟹,另一方面當(dāng)某一個在應(yīng)用中到處傳播的對象需要修改實例化的邏輯時蕾域,我們只需要修改其工廠代碼拷肌。

工廠模式可以分為以下三類

  • 簡單工廠
  • 工廠模式
  • 抽象工廠

其中簡單工廠并不屬于23種設(shè)計模式

簡單工廠

顧名思義,簡單工廠相比其他兩種工廠類的模式相對簡單不少旨巷。它是由一個工廠對象來決定創(chuàng)建出哪一種產(chǎn)品的示例
下面巨缘,我們以生產(chǎn)Cpu的例子來進(jìn)行講解

  1. 首先定義一個生產(chǎn)Cpu的接口
public interface Cpu
{
    void produce();
}
  1. 分別定義其不同的實現(xiàn)類
public class KirinCpu implements Cpu
{
    @Override
    public void produce()
    {
        System.out.println("華為麒麟處理器");
    }
}
public class MtkCpu implements Cpu
{
    @Override
    public void produce()
    {
        System.out.println("聯(lián)發(fā)科處理器");
    }
}

public class SnapdragonCpu implements Cpu
{
    @Override
    public void produce()
    {
        System.out.println("高通驍龍?zhí)幚砥?);
    }
}
  1. 創(chuàng)建一個生產(chǎn)Cpu的工廠類,根據(jù)傳入的參數(shù)返回一個對應(yīng)的對象
public class CpuFactory
{
    public static Cpu getCpu(String type)
    {
        if(type.equals("Kirin"))
        {
            return new KirinCpu();
        }else if(type.equals("Mtk"))
        {
            return new MtkCpu();
        }else if(type.equals("Snapdragon"))
        {
            return new SnapdragonCpu();
        }
        return null;
    }
}

4.這樣采呐,我們在客戶端應(yīng)用層就可以直接通過工廠來獲取想要的Cpu

public class Client
{
    public static void main(String[] args)
    {
        Cpu cpu = CpuFactory.getCpu("Mtk");
        if(cpu != null)
        {
            cpu.produce();
        }
    }
}

如果不采用簡單工廠若锁,我們需要在我們的應(yīng)用層來處理產(chǎn)品類的具體實現(xiàn),而采用簡單工廠后斧吐,產(chǎn)品類的具體實現(xiàn)放在了工廠里拴清。這樣就對我們的應(yīng)用層進(jìn)行了解耦

簡單工廠的類UML圖

缺點

  • 工廠類的職責(zé)相對較重,所有產(chǎn)品的實現(xiàn)都在一個工廠方法里執(zhí)行
  • 不符合開閉原則(即對修改關(guān)閉会通,擴(kuò)展開放)口予,當(dāng)我們新增一個產(chǎn)品的實現(xiàn)類的時候,需要對工廠方法進(jìn)行修改

改進(jìn)
我們可以通過反射來改進(jìn)我們的工廠方法

public class CpuFactory
{
    public static Cpu getCpu(Class<? extends Cpu> c)
    {
        Cpu cpu = null;
        try
        {
            cpu = c.newInstance();
        } catch (InstantiationException | IllegalAccessException e)
        {
            e.printStackTrace();
        }
        return cpu;
    }
}

簡單工廠模式的應(yīng)用

jdk中Calendar類的getInstance()方法


其有以上的重載方法涕侈,但最終都會調(diào)用createCalendar(TimeZone zone,Locale aLocale)方法來生成一個Calendar對象沪停,如果指定TimeZone和Locale則會把指定的值作為參數(shù)傳遞給createCalendar方法,如果沒有則先獲得系統(tǒng)默認(rèn)值然后再傳遞裳涛。
其方法聲明如下

    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;

        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 (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;
    }

Calendar類有以下實現(xiàn)


我們可以發(fā)現(xiàn)在createCalendar方法內(nèi)通過對傳入的TimeZoneLocale的值進(jìn)行判斷木张,來生成不同的Calendar對象

jdbc中數(shù)據(jù)庫連接的獲取
我們在寫jdbc程序時,首先進(jìn)行的是Class.forName()注冊驅(qū)動端三,然后通過DriverManager.getConnection方法來獲取數(shù)據(jù)庫的連接舷礼。
在這里以mysql為例。當(dāng)執(zhí)行完Class.forName("com.mysql.jdbc.Driver")郊闯,會完成類的加載妻献,而在類加載初始化過程中會對靜態(tài)代碼塊里的內(nèi)容進(jìn)行執(zhí)行,打開其源碼团赁,我們發(fā)現(xiàn)其在里面完成了驅(qū)動的注冊

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {
    }

    static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}

DriverMananger里有以下一行代碼聲明

private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>(); 

DriverManager.registerDriver(new Driver())方法會生成一個DriverInfo育拨,然后將其添加到此CopyOnWriteArrayList里面,至此欢摄,驅(qū)動的注冊完成熬丧。


而對于DriverManager.getConnection,雖然其由好幾種重載方法怀挠,但最終會都是調(diào)用getConnection(String url, java.util.Properties info, Class<?> caller)方法析蝴,打開其源碼

 private static Connection getConnection(
        String url, java.util.Properties info, Class<?> caller) throws SQLException {
        /*
         * When callerCl is null, we should check the application's
         * (which is invoking this class indirectly)
         * classloader, so that the JDBC driver class outside rt.jar
         * can be loaded from here.
         */
        ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
        synchronized(DriverManager.class) {
            // synchronize loading of the correct classloader.
            if (callerCL == null) {
                callerCL = Thread.currentThread().getContextClassLoader();
            }
        }

        if(url == null) {
            throw new SQLException("The url cannot be null", "08001");
        }

        println("DriverManager.getConnection(\"" + url + "\")");

        // Walk through the loaded registeredDrivers attempting to make a connection.
        // Remember the first exception that gets raised so we can reraise it.
        SQLException reason = null;

        for(DriverInfo aDriver : registeredDrivers) {
            // If the caller does not have permission to load the driver then
            // skip it.
            if(isDriverAllowed(aDriver.driver, callerCL)) {
                try {
                    println("    trying " + aDriver.driver.getClass().getName());
                    Connection con = aDriver.driver.connect(url, info);
                    if (con != null) {
                        // Success!
                        println("getConnection returning " + aDriver.driver.getClass().getName());
                        return (con);
                    }
                } catch (SQLException ex) {
                    if (reason == null) {
                        reason = ex;
                    }
                }

            } else {
                println("    skipping: " + aDriver.getClass().getName());
            }

        }

        // if we got here nobody could connect.
        if (reason != null)    {
            println("getConnection failed: " + reason);
            throw reason;
        }

        println("getConnection: no suitable driver found for "+ url);
        throw new SQLException("No suitable driver found for "+ url, "08001");
    }

我們會發(fā)現(xiàn)其通過遍歷已經(jīng)注冊的驅(qū)動害捕,如果驅(qū)動正常,則直接返回該驅(qū)動生成的
Connection闷畸。
在這里驅(qū)動的注冊相當(dāng)于工廠方法的參數(shù)的傳遞尝盼,然后就可以通過getConnection方法獲得該驅(qū)動所對應(yīng)的連接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市腾啥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌冯吓,老刑警劉巖倘待,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異组贺,居然都是意外死亡凸舵,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門失尖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來啊奄,“玉大人,你說我怎么就攤上這事掀潮」娇洌” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵仪吧,是天一觀的道長庄新。 經(jīng)常有香客問我,道長薯鼠,這世上最難降的妖魔是什么择诈? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮出皇,結(jié)果婚禮上羞芍,老公的妹妹穿的比我還像新娘。我一直安慰自己郊艘,他們只是感情好荷科,可當(dāng)我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著纱注,像睡著了一般步做。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上奈附,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天落塑,我揣著相機(jī)與錄音,去河邊找鬼傍菇。 笑死,一個胖子當(dāng)著我的面吹牛勉盅,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播顶掉,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼草娜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了痒筒?” 一聲冷哼從身側(cè)響起宰闰,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎簿透,沒想到半個月后移袍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡老充,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年葡盗,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片啡浊。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡觅够,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出巷嚣,到底是詐尸還是另有隱情喘先,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布廷粒,位于F島的核電站苹祟,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏评雌。R本人自食惡果不足惜树枫,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望景东。 院中可真熱鬧砂轻,春花似錦、人聲如沸斤吐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽和措。三九已至庄呈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間派阱,已是汗流浹背诬留。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人文兑。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓盒刚,卻偏偏與公主長得像,于是被迫代替她去往敵國和親绿贞。 傳聞我的和親對象是個殘疾皇子因块,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內(nèi)容

  • JDBC基礎(chǔ)知識 一、采用JDBC訪問數(shù)據(jù)庫的基本步驟: A.載入JDBC驅(qū)動程序 B.定義連接URL ...
    java日記閱讀 3,849評論 0 20
  • 本文主要內(nèi)容 1籍铁、JDBC 2涡上、DBUtils 01JDBC概念和數(shù)據(jù)庫驅(qū)動程序 A: JDBC概念和數(shù)據(jù)庫驅(qū)動程...
    勝浩_ae28閱讀 397評論 0 0
  • 設(shè)計模式分類 總體來說設(shè)計模式分為三大類:創(chuàng)建型模式,共五種:工廠方法模式拒名、抽象工廠模式吩愧、單例模式、建造者模式靡狞、原...
    lifeline丿毅閱讀 1,215評論 0 2
  • 一耻警、簡歷準(zhǔn)備 1隔嫡、個人技能 (1)自定義控件甸怕、UI設(shè)計、常用動畫特效 自定義控件 ①為什么要自定義控件腮恩? Andr...
    lucas777閱讀 5,202評論 2 54
  • 白鶴傷愈行梢杭, 知報謝遇恩; 留下一支...
    穿越荒城閱讀 306評論 0 1