vlambda博客
学习文章列表

JDK源码解读单例模式与工厂模式

JDK源码解读单例模式与工厂模式

0x01:单例模式

  • java.lang.Runtime

public class Runtime {
    //单例成员变量
    private static Runtime currentRuntime = new Runtime();

    //获取单例
    public static Runtime getRuntime() {
        return currentRuntime;
    }

    //私有构造方法
    private Runtime() {}

   //省略 .....
}

       从源码看标准的饿汉模式,Runtime类封装了Java运行时的环境。每一个java程序实际上都是启动了一个JVM进程,那么每个JVM进程都是对应这一个Runtime实例,此实例是由JVM为其实例化的。每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。

        在Java的GUI编程接口上也有几个单例模式的实现,但是Java的GUI编程在国内几乎被淘汰了,这里就不介绍了。


0x02:工厂模式

  • java.util.Calendar

public abstract class Calendar implements SerializableCloneableComparable<Calendar{
     public static Calendar getInstance(TimeZone zone,
                                       Locale aLocale)
{
        return createCalendar(zone, aLocale);
    }

    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) {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使用了简单工厂模式,通过getInstance()方法进去,而getInstance()方法调用了createCalendar()方法。

JDK源码解读单例模式与工厂模式

  • javax.xml.parsers.DocumentBuilderFactory

    public static DocumentBuilderFactory newInstance() {
        return FactoryFinder.find(
                DocumentBuilderFactory.class, 
                "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl");
    }

    public static DocumentBuilderFactory newInstance(String factoryClassName, ClassLoader classLoader){
            return FactoryFinder.newInstance(DocumentBuilderFactory.class,
                        factoryClassName, classLoader, false);
    }

    public abstract DocumentBuilder newDocumentBuilder()
        throws ParserConfigurationException
;

       javax.xml.parses包的DocumentBuilderFactory用于创建DOM模式的解析器对象,DocumentBuilderFactory是一个抽象工厂类,它不能直接实例化,但该类提供了一个newInstance方法,这个方法会根据本地平台默认安装的解析器,自动创建一个工厂的对象并返回。

    从DocumentBuilderFactory源码上看提供了一个默认的实现DocumentBuilderFactoryImpl.java,看到该类的newDocumentBuilder,可以看出只要调用newInstance()方法就会返回一个新的DocumentBuilder 对象

   public DocumentBuilder newDocumentBuilder()
        throws ParserConfigurationException
    
{
        if (grammar != null && attributes != null) {
            if (attributes.containsKey(JAXPConstants.JAXP_SCHEMA_LANGUAGE)) {
                throw new ParserConfigurationException(
                        SAXMessageFormatter.formatMessage(null,
                        "schema-already-specified"new Object[] {JAXPConstants.JAXP_SCHEMA_LANGUAGE}));
            }
            else if (attributes.containsKey(JAXPConstants.JAXP_SCHEMA_SOURCE)) {
                throw new ParserConfigurationException(
                        SAXMessageFormatter.formatMessage(null,
                        "schema-already-specified"new Object[] {JAXPConstants.JAXP_SCHEMA_SOURCE}));
            }
        }

        try {
            return new DocumentBuilderImpl(this, attributes, features, fSecureProcess);
        } catch (SAXException se) {
            throw new ParserConfigurationException(se.getMessage());
        }
    }
JDK源码解读单例模式与工厂模式

扫码二维码

获取更多精彩

Java乐园

有用!分享+在看☟