日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

简单工厂模式在Logback源码以及JDK源码中的应用

發(fā)布時間:2023/12/18 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 简单工厂模式在Logback源码以及JDK源码中的应用 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

創(chuàng)建型模式

目錄

一、簡單工廠模式在Logback源碼以及JDK源碼中的應(yīng)用

1、簡單工廠模式

1.1?簡單工廠模式的UML類圖

1.2?日常生活中看簡單工廠模式

1.3?具體例子

2、簡單工廠模式在Logback源碼中的應(yīng)用

3、簡單工廠模式在JDK源碼中的應(yīng)用

3.1 Calendar 類為例簡單工廠模式

3.2 JDBC簡單工廠模式

4、簡單工廠模式的優(yōu)缺點

4.1 簡單工廠模式的優(yōu)點

4.2 簡單工廠模式的缺點

4.3 簡單工廠模式的適用環(huán)境


一、簡單工廠模式在Logback源碼以及JDK源碼中的應(yīng)用

1、簡單工廠模式

簡單工廠模式(Simple Factory Pattern):又稱為靜態(tài)工廠方法(Static Factory Method)模式,它屬于創(chuàng)建型模式。簡單工廠模式的實質(zhì)是由一個工廠類根據(jù)傳入的參數(shù),動態(tài)決定應(yīng)該創(chuàng)建哪一個產(chǎn)品類(這些產(chǎn)品類繼承或?qū)崿F(xiàn)一個父類或接口)的實例。

1.1?簡單工廠模式的UML類圖

1.2?日常生活中看簡單工廠模式

就拿巴扎黑理發(fā)這件事來說,服務(wù)員就充當了工廠類,她根據(jù)巴扎黑想要剪的價位來安排一位合適的理發(fā)師。理發(fā)師這個稱謂就相當于抽象產(chǎn)品,它描述了所有理發(fā)師都具備的能力——理發(fā)。服務(wù)員安排的這位總監(jiān)就相當于具體產(chǎn)品。
簡單工廠模式中,對于某個具體業(yè)務(wù)而言,client 無需知道由誰來處理這個業(yè)務(wù),怎么處理,它只需告訴工廠類這個業(yè)務(wù)的類型,并調(diào)用工廠類提供的靜態(tài)方法拿到一個具體的產(chǎn)品,然后調(diào)用產(chǎn)品的業(yè)務(wù)方法來完成業(yè)務(wù)。就像巴扎黑去餐廳吃飯,他只要告訴服務(wù)員他想吃什么,然后自然會有一位師傅幫他做好,自己根本就不需要關(guān)心這個師傅是誰以及怎么做出這道美味菜肴。這樣看來,吃飯這件事也不麻煩。
但是設(shè)想一下,巴扎黑很早就起床了,他想自己做菜來犒勞自己,他有充足的時間來準備。首先他得考慮想要吃什么,于是有了下面的思考:

// 偽代碼 prepareToEat(food) {if (food == "魚丸粗面") {去買魚丸和粗面;放在鍋里燒; ... } else if (food == "大盤雞") {去菜場挑只雞讓大媽殺了,剁好裝袋;買洋蔥和其他配料;把雞肉浸水洗凈;洋蔥切好;...} else if (food == "紅燒肉") {去菜場挑一塊五花肉; // 一定要買帶肥肉的,不然燒出來很難吃切塊洗凈放料酒浸泡;鍋里放油煸炒肉塊;...}... }

要想吃點好的,腦袋里還得裝一本厚厚的菜譜,想要嘗嘗新菜,還得不斷豐富大腦里的菜譜,著實麻煩。有時候腦袋不夠使,還會把菜譜記錯,倒不如直接去餐廳點菜吃來的省事兒。

1.3?具體例子

1.3.1 場景

實現(xiàn)一個簡單的翻譯功能,要求:能夠?qū)⒁欢沃形奈谋痉g成不同的語言版本

1.3.2 代碼

要實現(xiàn)翻譯,我們得有一個翻譯器。我們先定義一個抽象的翻譯器(AbstractTranslator),用于描述所有翻譯器都具備的功能——翻譯(translate)

/*** 翻譯器抽象類* 抽象產(chǎn)品,定義產(chǎn)品必須實現(xiàn)的方法** @author piaolingluo* @date 2017-11-08*/ public abstract class AbstractTranslator {@Autowiredprotected BaiduConfig baiduConfig;/*** 翻譯** @param content 待翻譯的內(nèi)容* @return 翻譯的得到的內(nèi)容*/public abstract String translate(String content); }

再定義一個具體的翻譯器——英語翻譯器(EnglishTranslator),繼承AbstractTranslator,它能將一段中文翻譯成英文

/*** 英語翻譯器* 具體產(chǎn)品** @author piaolingluo* @date 2017-11-08*/ @Service public class EnglishTranslator extends AbstractTranslator {@Autowiredprivate Gson gson;@Overridepublic String translate(String content) {TransApi api = new TransApi(baiduConfig.getAppId(), baiduConfig.getSecurityKey());String response = api.getTransResult(content, "auto", "en");TransResult result = gson.fromJson(response, TransResult.class);return result.getTransResult().get(0).getDst();} }

再定義一個具體的翻譯器——日語翻譯器(JapaneseTranslator),繼承AbstractTranslator,它能將一段中文翻譯成日語

/*** 日語翻譯器* 具體產(chǎn)品** @author piaolingluo* @date 2017-11-08*/ @Service public class JapaneseTranslator extends AbstractTranslator {@Autowiredprivate Gson gson;@Overridepublic String translate(String content) {TransApi api = new TransApi(baiduConfig.getAppId(), baiduConfig.getSecurityKey());String response = api.getTransResult(content, "auto", "jp");TransResult result = gson.fromJson(response, TransResult.class);return result.getTransResult().get(0).getDst();} }

接著,我們定義系統(tǒng)能能翻譯的語言有哪些,如果后續(xù)支持新的語言,可以追加

/*** 語言枚舉* 定義系統(tǒng)能翻譯的語言** @author piaolingluo* @date 2017-11-08*/ @Getter public enum LanguageEnum {CHINESE("chinese", "中文"),ENGLISH("english", "英語"),JAPANESE("japanese", "日語");private String code;private String name;LanguageEnum(String code, String name) {this.code = code;this.name = name;}public static LanguageEnum valueOfLanguage(String code) {return Stream.of(values()).filter(languageEnum -> languageEnum.getCode().equals(code)).findFirst().orElse(null);} }

接著,比較重要的一點是為不同的語言指定各自的實例,后續(xù)如果支持新的語言,可以在此擴展

/*** 語言類型與翻譯器實例的映射** @author piaolingluo* @date 2017-11-08*/ @Getter public enum TranslatorEnum {ENGLISH_TRANSLATOR(LanguageEnum.ENGLISH, "englishTranslator"),JAPANESE_TRANSLATOR(LanguageEnum.JAPANESE, "japaneseTranslator");/*** 語言*/private LanguageEnum language;/*** 具體翻譯器處理bean的名字*/private String translatorName;TranslatorEnum(LanguageEnum language, String translatorName) {this.language = language;this.translatorName = translatorName;}public static TranslatorEnum valueOfTranslator(String translatorName) {return Stream.of(values()).filter(translatorEnum -> translatorEnum.getTranslatorName().equals(translatorName)).findFirst().orElse(null);}public static LanguageEnum languageOfTranslator(String translatorName) {Optional<TranslatorEnum> optional = Optional.ofNullable(valueOfTranslator(translatorName));return optional.isPresent() ? optional.get().getLanguage() : null;} }

最最重要的就是編寫這個工廠類(Factory),初始化的時候,將所有的翻譯器按各自能處理的語言類型存放在 TRANSLATOR_MAP 里,并提供一個靜態(tài)方法,能夠根據(jù)不同的語言拿到具體的翻譯器

/*** 工廠** @author piaolingluo* @date 2017-11-08*/ @Component public class Factory {private static final Map<LanguageEnum, AbstractTranslator> TRANSLATOR_MAP = new HashMap<>();@Autowiredprivate ApplicationContext applicationContext;@PostConstructpublic void init() {applicationContext.getBeansOfType(AbstractTranslator.class).entrySet().stream().filter(entry -> null != TranslatorEnum.valueOfTranslator(entry.getKey())).forEach(entry -> TRANSLATOR_MAP.put(TranslatorEnum.languageOfTranslator(entry.getKey()),entry.getValue()));}/*** 根據(jù)語言枚舉拿到指定語言的翻譯器** @param languageEnum 語言枚舉* @return 指定語言的翻譯器* @throws Exception 當拿不到翻譯器時,拋出此異常*/public static AbstractTranslator getTranslator(LanguageEnum languageEnum) throws Exception {AbstractTranslator translator = TRANSLATOR_MAP.get(languageEnum);if (null == translator) {throw new Exception("無法翻譯成這種語言");}return translator;}/*** 根據(jù)語言編碼拿到指定語言的翻譯器** @param languageCode 語言編碼* @return 指定語言的翻譯器* @throws Exception 當拿不到翻譯器時,拋出此異常*/public static AbstractTranslator getTranslator(String languageCode) throws Exception {return getTranslator(LanguageEnum.valueOfLanguage(languageCode));} }

然后我們寫個 TranslateController ,接收指定的語言編碼和待翻譯的文本,返回翻譯后的文本

/*** 翻譯服務(wù)** @author piaolingluo* @date 2017-11-08*/ @RestController @RequestMapping("translate") public class TranslateController {@GetMapping("{code}")public ResponseEntity<String> translate(@PathVariable("code") String code,@RequestParam(value = "content", required = false) String content) {try {// 調(diào)用工廠類的靜態(tài)方法,傳入語言編碼,拿到具體的翻譯器實例進行翻譯return ResponseEntity.ok(Factory.getTranslator(code).translate(content));} catch (Exception e) {return ResponseEntity.ok(e.getMessage());}} }

最后我們測試一下。

demo完整代碼請戳這里

2、簡單工廠模式在Logback源碼中的應(yīng)用

在大家經(jīng)常使用的 Logback 中,也可以看到 LoggerFactory 中有多個重載的方法 getLogger()。

public static Logger getLogger(String name) {ILoggerFactory iLoggerFactory = getILoggerFactory();return iLoggerFactory.getLogger(name);}public static Logger getLogger(Class clazz) {return getLogger(clazz.getName());}

3、簡單工廠模式在JDK源碼中的應(yīng)用

3.1 Calendar 類為例簡單工廠模式

可以說簡單工廠模式在 JDK 源碼中無處不在,下面以 Calendar 類為例講解簡單工廠模式在 JDK 源碼中的應(yīng)用。Calendar 類的 getInstance() 方法源碼如下。

public static Calendar getInstance() {Calendar cal = createCalendar(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT));cal.sharedZone = true;return cal; }

進入?createCalendar() 方法中,源碼如下:

private static Calendar createCalendar(TimeZone zone, Locale aLocale) {Calendar cal = null;String caltype = aLocale.getUnicodeLocaleType("ca");if (caltype == null) {// Calendar type is not specified.// If the specified locale is a Thai locale,// returns a BuddhistCalendar instance.if ("th".equals(aLocale.getLanguage())&& ("TH".equals(aLocale.getCountry()))) {cal = new BuddhistCalendar(zone, aLocale);} else {cal = new GregorianCalendar(zone, aLocale);}} else if (caltype.equals("japanese")) {cal = new JapaneseImperialCalendar(zone, aLocale);} else if (caltype.equals("buddhist")) {cal = new BuddhistCalendar(zone, aLocale);} else {// Unsupported calendar type.// Use Gregorian calendar as a fallback.cal = new GregorianCalendar(zone, aLocale);}return cal; }

Calendar 的 UML 類圖如下:

3.2 JDBC簡單工廠模式

當我們需要MySQL數(shù)據(jù)庫的驅(qū)動時,我們就傳MySQL的參數(shù),用Oracle的就傳相應(yīng)的參數(shù)。在寫JDBC的時候,JDK來實現(xiàn)的時候,

Class.forName("com.mysql.jdbc.Driver");

通過Class.forName把mysql的驅(qū)動加載進來,那如果寫ORACLE的驅(qū)動呢,這里就變成對應(yīng)的ORACLE的JDBC的jar包,ORACLE的driver類,然后調(diào)用DriverManager的getConnection方法,

@CallerSensitivepublic static Connection getConnection(String url)throws SQLException {java.util.Properties info = new java.util.Properties();return (getConnection(url, info,Reflection.getCallerClass())); }

獲取對應(yīng)的數(shù)據(jù)庫連接,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這種方式,直接通過反射拿到對應(yīng)的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循環(huán),在遍歷注冊的一個驅(qū)動,
?
private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
?
并且它是CopyOnWriteArrayList,里面是DriverInfo,初始化的時候他是一個空的,具體是什么時候完成注冊的呢,

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 DriverManagerthrow new NullPointerException();}println("registerDriver: " + driver);}

如果不存在就往里放

if(driver != null) {registeredDrivers.addIfAbsent(new DriverInfo(driver, da));}

4、簡單工廠模式的優(yōu)缺點

4.1 簡單工廠模式的優(yōu)點

工廠類是整個模式的關(guān)鍵,包含了必要的邏輯判斷,根據(jù)外界給定的信息,決定究竟應(yīng)該創(chuàng)建哪個具體類的對象。通過使用工廠類,外界可以從直接創(chuàng)建具體產(chǎn)品對象的尷尬局面擺脫出來,僅僅需要負責“消費”對象就可以了。而不必管這些對象究竟如何創(chuàng)建及如何組織的。明確了各自的職責和權(quán)利,有利于整個軟件體系結(jié)構(gòu)的優(yōu)化。

4.2 簡單工廠模式的缺點

由于工廠類集中了所有實例的創(chuàng)建邏輯,違反了高內(nèi)聚責任分配原則,將全部創(chuàng)建邏輯集中到了一個工廠類中。它所能創(chuàng)建的類只能是事先考慮到的,如果需要添加新的類,就需要改變工廠類了。

4.3 簡單工廠模式的適用環(huán)境

(1) 工廠類負責創(chuàng)建的對象比較少:由于創(chuàng)建的對象較少,不會造成工廠方法中的業(yè)務(wù)邏輯太過復(fù)雜;
(2) 客戶端只知道傳入工廠類的參數(shù),對于如何創(chuàng)建對象不關(guān)心:客戶端既不需要關(guān)心創(chuàng)建細節(jié),甚至連類名都不需要記住,只需要知道類型所對應(yīng)的參數(shù)。



?


參考文章:
https://www.jianshu.com/p/72567cc1d63f

http://c.biancheng.net/view/8387.html

https://www.cnblogs.com/thiaoqueen/p/11169924.html

?

總結(jié)

以上是生活随笔為你收集整理的简单工厂模式在Logback源码以及JDK源码中的应用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。