[01][01][03] 工廠模式詳解

工廠模式分爲三種類型html

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

1. 簡單工廠模式

指由一個工廠對象決定建立出哪種產品類的實例java

1.1 代碼實現

1.1.1 產品抽象類

public interface ICourse {
    /**
     * 錄製課程
     */
    void record();
}

1.1.2 具體產品類

public class JavaCourse implements ICourse {
    /**
     * 錄製 java 課程
     */
    @Override
    public void record() {
        System.out.println("正在錄製 java 課程");
    }
}

1.1.3 簡單工廠類

public class CourseFactory {

    /**
     * 經過名稱建立對象
     * @param name
     * @return
     */
    public ICourse createByName(String name) {
         if ("java".equals(name)) {
             return new JavaCourse();
         } else {
             return null;
         }
    }

    /**
     * 經過類路徑建立對象
     * @param classPath
     * @return
     */
    public ICourse createByClassPath(String classPath) {
        try {
            if (StringUtils.isNotBlank(classPath)) {
                return (ICourse) Class.forName(classPath).newInstance();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 經過類建立對象
     * @param className
     * @return
     */
    public ICourse createByClass(Class className) {
        try {
            if (null != className) {
                return (ICourse) className.newInstance();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

1.1.4 測試類

public class SimelpFactoryTest {

    public static void main(String[] args) {
        CourseFactory courseFactory = new CourseFactory();

        // 經過類名建立對象
        ICourse nameCourse = courseFactory.createByName("java");
        nameCourse.record();

        // 經過類路徑建立對象
        ICourse classNameCourse = courseFactory.createByClassPath("com.zhunongyun.toalibaba.designpatterns.factory.common.JavaCourse");
        classNameCourse.record();

        // 經過類建立對象
        ICourse classCourse = courseFactory.createByClass(JavaCourse.class);
        classCourse.record();

        ICourse pythonCourse = courseFactory.createByName("python");
        pythonCourse.record();
    }
}

1.2 適用場景

  • 工廠類負責建立的對象較少
  • 客戶端只須要傳入工廠類的參數,對於如何建立對象的邏輯不須要關心

1.3 優勢/缺點

1.3.1 優勢

  • 只須要傳入一個正確的參數就能夠獲取你所須要的對象,無需知道其建立細節

1.3.2 缺點

  • 工廠類的職責相對太重,增長新的產品時須要修改工廠類的判斷邏輯,違背了開閉原則
  • 不易於擴展過於複雜的產品結構

1.4 源碼分析

1.4.1java.util 下的 Calendar

Calendar 是一個日曆工具,使用簡單工廠模式建立實體類Calendarcalendar=Calendar.getInstance();python

Calendar 的 getInstance()的代碼就是經過簡單工廠的方式去建立 Calendar 對象ide

public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {
    public static Calendar getInstance()
    {
        return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
    }

    ......

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

1.4.2org.slf4j 下的 LoggerFactory

LoggerFactory 是日誌工廠類,經過簡單工廠建立對象Loggerlogger=LoggerFactory.getLogger("xx");工具

LoggerFactory 的 getLogger()的代碼就是經過簡單工廠的方式去建立 Logger 對象源碼分析

public final class LoggerFactory {
    public static Logger getLogger(String name) {
        ILoggerFactory iLoggerFactory = getILoggerFactory();
        return iLoggerFactory.getLogger(name);
    }

    public static Logger getLogger(Class<?> clazz) {
        Logger logger = getLogger(clazz.getName());
        if (DETECT_LOGGER_NAME_MISMATCH) {
            Class<?> autoComputedCallingClass = Util.getCallingClass();
            if (autoComputedCallingClass != null && nonMatchingClasses(clazz, autoComputedCallingClass)) {
                Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", logger.getName(), autoComputedCallingClass.getName()));
                Util.report("See http://www.slf4j.org/codes.html#loggerNameMismatch for an explanation");
            }
        }
        return logger;
    }
}

2. 工廠方法模式

指定義一個建立對象的接口,但讓實現這個接口的類來決定實例化哪一個類,工廠方法讓類的實例化推遲到子類中進行測試

2.1 代碼實現

  • 產品抽象類日誌

    public interface ICourse {
    /**
    * 錄製課程
    */
    void record();
    }
  • 具體產品類code

    public class JavaCourse implements ICourse {
    /**
    * 錄製 java 課程
    */
    @Override
    public void record() {
    System.out.println("正在錄製 java 課程");
    }
    }
  • 建立對象的工廠接口類orm

    public interface ICourseFactory {
    /**
    * 建立實體類
    * @return
    */
    ICourse create();
    }
  • 具體產品工廠類

    public class JavaCourseFactory implements ICourseFactory {
    /**
    * 建立 java 課程實體類
    * @return
    */
    @Override
    public ICourse create() {
    return new JavaCourse();
    }
    }
  • 測試類

    public class FactoryMethodTest {
    public static void main(String[] args) {
    ICourseFactory courseFactory = new JavaCourseFactory();
    ICourse course = courseFactory.create();
    course.record();
    }
    }

2.2 適用場景

  • 建立對象須要大量重複的代碼
  • 客戶端(應用層)不依賴於產品類實例如何被建立,實現等細節
  • 一個類經過其子類來指定建立哪一個對象

2.3 優/缺點

2.3.1 優勢

  • 用戶只需關心所需產品對應的工廠,無需關心建立細節
  • 加入新產品符合開閉原則,提升了系統的可擴展性

2.3.2 缺點

  • 類的個數容易過多,增長了代碼結構的複雜度
  • 增長了系統的抽象性和理解難度

2.4 源碼分析

2.4.1org.slf4j 下的 LoggerFactory

LoggerFactory 的 getLogger()的代碼中ILoggerFactory iLoggerFactory = getILoggerFactory();,經過工廠方法模式建立出具體 Logger 的工廠類

public final class LoggerFactory {
    public static Logger getLogger(String name) {
        ILoggerFactory iLoggerFactory = getILoggerFactory();
        return iLoggerFactory.getLogger(name);
    }

    public static ILoggerFactory getILoggerFactory() {
        if (INITIALIZATION_STATE == 0) {
            Class var0 = LoggerFactory.class;
            synchronized(LoggerFactory.class) {
                if (INITIALIZATION_STATE == 0) {
                    INITIALIZATION_STATE = 1;
                    performInitialization();
                }
            }
        }

        switch(INITIALIZATION_STATE) {
        case 1:
            return SUBST_FACTORY;
        case 2:
            throw new IllegalStateException("org.slf4j.LoggerFactory in failed state. Original exception was thrown EARLIER. See also http://www.slf4j.org/codes.html#unsuccessfulInit");
        case 3:
            return StaticLoggerBinder.getSingleton().getLoggerFactory();
        case 4:
            return NOP_FALLBACK_FACTORY;
        default:
            throw new IllegalStateException("Unreachable code");
        }
    }
}

3. 抽象工廠模式

指提供一個建立一系列相關或相互依賴對象的接口,無需指定他們具體的類

3.1 產品等級與產品族

  • 產品等級結構:產品等級結構即產品的繼承結構,如一個抽象類是手機,其子類有華爲手機,小米手機,蘋果手機,則抽象手機與具體品牌的手機之間構成了一個產品等級結構,抽象手機是父類,而具體品牌的手機是其子類

  • 產品族:在抽象工廠模式中,產品族是指由同一個工廠生產的,位於不一樣產品等級結構中的一組產品,如華爲工廠生產的華爲手機,華爲筆記本,華爲手機位於手機產品等級結構中,華爲筆記本位於筆記本產品等級結構中,華爲手機,華爲筆記本構成了一個產品族

3.2 代碼實現

  • 產品抽象類 java public interface ICourse {
    /**
    * 錄製課程
    */
    void record();
    }
public interface INote {
    /**
     * 編寫課程筆記
     */
    void write();
}
public interface IVideo {
    /**
     * 處理課程視頻
     */
    void handle();
}
  • 具體產品類 java public class JavaCourse implements ICourse {
    /**
    * 錄製 java 課程
    */
    @Override
    public void record() {
    System.out.println("正在錄製 java 課程");
    }
    }
public class JavaNote implements INote {
    @Override
    public void write() {
        System.out.println("正在編寫 java 課程筆記");
    }
}
public class JavaVideo implements IVideo {
    @Override
    public void handle() {
        System.out.println("正在處理 java 課程視頻");
    }
}
  • 建立對象的工廠接口類

    public interface ICourseFactory {
    /**
    * 錄製課程
    * @return
    */
    ICourse createCourse();
    /**
    * 編寫課程筆記
    * @return
    */
    INote creatNode();
    /**
    * 處理課程視頻
    * @return
    */
    IVideo createVideo();
    }
  • 具體產品工廠類

    public class JavaCourseFactory implements ICourseFactory {
    @Override
    public ICourse createCourse() {
    return new JavaCourse();
    }
    @Override
    public INote creatNode() {
    return new JavaNote();
    }
    @Override
    public IVideo createVideo() {
    return new JavaVideo();
    }
    }
  • 測試類

    public class AbstractFactoryTest {
    public static void main(String[] args) {
    ICourseFactory courseFactory = new JavaCourseFactory();
    // 錄製 java 課程
    courseFactory.createCourse().record();
    // 編寫 java 課程筆記
    courseFactory.creatNode().write();
    // 處理 java 課程視頻
    courseFactory.createVideo().handle();
    }
    }

3.3 適用場景

  • 客戶端(應用層)不依賴於產品類實例如何建立,實現等細節
  • 強調一系列相關的產品對象(同屬於同一產品族)一塊兒使用建立對象須要大量重複的代碼
  • 提供一個產品類的庫,全部的產品以一樣的接口出現,從而使客戶端不依賴於具體的實現

3.4 優/缺點

3.4.1 優勢

  • 具體產品在應用層代碼隔離,無需關心建立細節
  • 將一個系列的產品族統一到一塊兒建立

3.42 缺點

  • 規定了全部可能被建立的產品結集合,產品族中擴展新的產品困難,須要修改抽象工廠的接口
  • 增長系統的抽象性和理解難度

3.5 源碼分析

Spring 中的 AbstractBeanFactory 類

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {

    ......

    protected abstract boolean containsBeanDefinition(String var1);

    protected abstract BeanDefinition getBeanDefinition(String var1) throws BeansException;

    protected abstract Object createBean(String var1, RootBeanDefinition var2, @Nullable Object[] var3) throws BeanCreationException;
}

AbstactBeanFactory 的三個實現類:

  • AbstractAutowireCapableBeanFactory
  • XmlBeanFactory
  • DefaultListableBeanFactory

相關文章
相關標籤/搜索