簡單工廠(三)——JDK源碼中的簡單工廠

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類圖java

  除了日曆類還有JDBC,當咱們須要MySQL數據庫的驅動時,咱們就傳MySQL的參數,用Oracle的就傳相應的參數。
在寫JDBC的時候,JDK來實現的時候,
Class.forName("com.mysql.jdbc.Driver");
 
經過Class.forName把mysql的驅動加載進來,那若是寫ORACLE的驅動呢,這裏就變成對應的ORACLE的JDBC的jar包,ORACLE的driver類,而後調用DriverManager的getConnection方法,
      @CallerSensitive
      public static Connection getConnection(String url)
          throws SQLException {
          java.util.Properties info = new java.util.Properties();
          return (getConnection(url, info,Reflection.getCallerClass()));         
     }
獲取對應的數據庫鏈接,JDBC的過程也是很是簡單的,
      //  Worker method called by the public getConnection() methods.
    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");
    }
經過Class.forName這種方式,直接經過反射拿到對應的Video,只不過MSYQL這裏面仍是須要經過註冊的,
        // Walk through the loaded registeredDrivers attempting to locate someone
        // who understands the given URL.
        for (DriverInfo aDriver : registeredDrivers) {
            // If the caller does not have permission to load the driver then
            // skip it.
            if(isDriverAllowed(aDriver.driver, callerClass)) {
                try {
                    if(aDriver.driver.acceptsURL(url)) {
                        // Success!
                        println("getDriver returning " + aDriver.driver.getClass().getName());
                    return (aDriver.driver);
                    }

                } catch(SQLException sqe) {
                    // Drop through and try the next driver.
                }
            } else {
                println("    skipping: " + aDriver.driver.getClass().getName());
            }

        }

 由於這個能夠看出來它是一個for循環,在遍歷註冊的一個驅動,
 
private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
 
而且它是CopyOnWriteArrayList,裏面是DriverInfo,初始化的時候他是一個空的,具體是何時完成註冊的呢, mysql

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

 

這個時候就會在registerDriver(new Driver())這個方法裏面直接註冊這個Driver,那裏面的Driver天然就是MySQL的Driver,
public static synchronized void registerDriver(java.sql.Driver driver,

            DriverAction da)

        throws SQLException {

 

        /* Register the driver if it has not already been added to our list */

        if(driver != null) {

            registeredDrivers.addIfAbsent(new DriverInfo(driver, da));

        } else {

            // This is for compatibility with the original DriverManager

            throw new NullPointerException();

        }

 

        println("registerDriver: " + driver);

}
若是不存在就往裏放
if(driver != null) {

registeredDrivers.addIfAbsent(new DriverInfo(driver, da));

}

此外,logback中也有簡單工廠的影子。sql

public final class LoggerFactory

 

public static ILoggerFactory getILoggerFactory() {

    

}

最裏面有一個getLogger方法,數據庫

 

public static Logger getLogger(Class clazz) {

return getLogger(clazz.getName());

}

 

public static Logger getLogger(String name) {

ILoggerFactory iLoggerFactory = getILoggerFactory();

return iLoggerFactory.getLogger(name);

}

 

  這個還有個重載,一個是String name,還有一個是Class clazz,clazz是幹嗎的,是clazz.getName(),   設計模式

  首先getLogger根據咱們傳來的name,從iLoggerFactory裏面getLogger,先看一下   app

public interface ILoggerFactory   

  package org.slf4j;

  //抽象產品工廠

  public interface ILoggerFactory {

     //抽象工廠方法

      public Logger getLogger(String name);

 }

  很明顯ILoggerFactory它是一個接口,下面有一個方法,那這個呢是工廠方法,那在後面咱們也會講,這裏先過去,   框架

  後面咱們學習工廠方法的時候,再單獨來講,而後經過iLoggerFactory.getLogger,由於它是一個接口,確定有多個實現,ide

   

  LoggerContext   

  //具體工廠實現類

  public class LoggerContext extends ContextBase implements ILoggerFactory, LifeCycle {

  ...

      //具體工廠方法

      @Override

      public final Logger getLogger(final String name) {

       ...

      }

  這裏面咱們看一下,傳入的一個name,這裏面要返回Logger,這裏面對name進行了判斷,很明顯這個方法就是一個簡單工廠方法,   學習

  根據傳入的入參進行選擇哪一個Logger,那這個仍是很是簡單的,剛剛也說了,在咱們的LoggerFactory裏面,既存在了工廠方法,ui

   

  又存在了簡單工廠,因此設計模式在使用的時候,不必定要侷限在使用一種,例如這裏就是一個組合的使用,這個簡單工廠比較簡單,

 在不少源碼中也可以找到他的影子,在前面的JDK,Logback開源框架的,對於學習設計模式的講解呢,咱們在閱讀源碼的時候呢,

  還能夠以設計模式的角度,去聚焦源碼,這樣對咱們理解源碼也是有益處的 。

相關文章
相關標籤/搜索