部落格

  • 預防全球災難 末日種子庫收6萬新種子樣本

    摘錄自2020年2月25日中央社報導

    挪威北極圈內的「末日種子庫」今(25日)預計將收到來自世界各地的6萬個種子樣本。這個全球最大農作物儲藏庫為了保護作物免於全球性災難,而囤積各類種子。

    這些種子將寄存在挪威斯瓦巴群島(Svalbard)內斯匹次柏根島(Spitsbergen Island)朗葉比(Longyearbyen)附近的深山中,距離北極點(North Pole)約1000公里。

    法新社報導,掌管種子庫的作物信託基金(Crop Trust)執行長施密茲(Stefan Schmitz)說:「隨著氣候變遷和生物多樣性喪失的速度增加,針對瀕臨滅絕作物的拯救工作產生新的急迫性。」

    最新運送的一批將讓種子庫藏提升至約105萬種,這些種子放置在種子庫的三座地窖,這個種子庫被譽為糧食作物的「諾亞方舟」。

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計

    ※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務

    ※Google地圖已可更新顯示潭子電動車充電站設置地點!!

    ※帶您來看台北網站建置,台北網頁設計,各種案例分享

    ※小三通物流營運型態?

    ※快速運回,大陸空運推薦?

  • PM 2.5壟罩南亞 印度新德空污最嚴重

    摘錄自2020年2月25日中央社報導

    研究人員今(25日)發布報告指出,全球200座最受致命污染微粒衝擊的城市,有近9成位於中國和印度,其餘則集中在巴基斯坦與印尼等地。

    法新社報導,據IQAir Group與環保團體「綠色和平」(Greenpeace)聯合公布的2019全球空氣品質報告(2019 World Air Quality Report),孟加拉是PM2.5污染最嚴重的國家,接著是巴基斯坦、蒙古、阿富汗和印度;中國排名11。

    2019年,1000萬人以上的巨型都市中,PM2.5污染最嚴重的是印度首都新德里,其次依序為巴基斯坦的拉合爾(Lahore)、孟加拉首都達卡(Dhaka)、印度加爾各答(Kolkata)、中國臨沂和天津、印尼雅加達、中國武漢。

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

    ※台灣寄大陸海運貨物規則及重量限制?

    ※大陸寄台灣海運費用試算一覽表

    ※南投搬家前需注意的眉眉角角,別等搬了再說!

  • 金融業自省? 摩根大通警告客戶 氣候危機威脅人類

    環境資訊中心綜合外電;姜唯 編譯;林大利 審校

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

    ※網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

    ※想知道最厲害的台北網頁設計公司推薦、台中網頁設計公司推薦專業設計師”嚨底家”!!

    ※大陸寄台灣空運注意事項

    ※大陸海運台灣交貨時間多久?

  • 大雅加達地區一夜豪雨 再現洪患逾80處淹水

    摘錄自2020年2月25日中央社報導

    印尼大雅加達地區昨晚降下豪雨,根據印尼國家災害應變總署的統計,至今(25日)上午有87處淹水,部分地區水深達150公分,許多社區泡在水中,道路無法通行,交通混亂。

    印尼國家通訊社安塔拉(Antara)報導,氣象氣候暨地球物理局(BMKG)統計,雅加達北部的葛馬約蘭(Kemayoran)氣象站昨晚至今晨偵測到24小時278毫米的雨量,許多地區的雨量也都高達150毫米以上,達豪雨標準。

    蘇迪爾曼車站(Sudirman)、甘比爾車站(Gambir)等交通要塞因淹水關閉;雅加達快捷公車有36條路線停駛,12條路線改道,連接雅加達與近郊城市包括唐格朗(Tangerang)等多條高速公路也受到淹水影響,交通大打結。

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※專營大陸空運台灣貨物推薦

    ※台灣空運大陸一條龍服務

    ※評比南投搬家公司費用收費行情懶人包大公開

    ※南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!

  • 武漢肺炎延燒 泰非政府組織籲關野生動物市場

    摘錄自2020年02月26日中央社報導

    武漢肺炎蔓延全球,野生動物被懷疑是可能的傳染源。泰國非政府組織(NGO)今(26日)發布報告,呼籲大眾停止購買野生動物,亞洲各國政府應關閉所有野生動物交易市場。

    泰國非政府組織自由地(Freeland)與卓越分析中心販運部門(Analytical Center of Excellence on Trafficking)發布「東南亞的野生動物販運:演化、軌跡和如何組織販運」報告,提出上述呼籲。

    自由地創辦人蓋爾斯特(Steven Galster)在記者會中指出,野生動物交易衍生的疾病風險問題,不只在中國,也不會只在武漢肺炎。緬甸、越南和泰國都賣野生動物,例如穿山甲、烏龜、猴子等。

    自由地執行經理馬占達(Onkuri Majumdar)指出,大家關注2019年冠狀病毒疾病(COVID-19,武漢肺炎)可能是蝙蝠或穿山甲傳染給人類。但不要忘記,嚴重急性呼吸道症候群(SARS)、禽流感、伊波拉病毒(Ebola Virus)甚至愛滋病毒都是由動物傳給人類,撲殺這些動物並不是解決的辦法。她呼籲各國政府關閉野生動物交易市場,大眾停止購買野生動物。

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※帶您來了解什麼是 USB CONNECTOR  ?

    ※自行創業 缺乏曝光? 下一步”網站設計“幫您第一時間規劃公司的門面形象

    ※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

    ※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※試算大陸海運運費!

  • 航運業減碳新招 看上阿摩尼亞

    摘錄自2020年02月20日台灣醒報報導

    航運業減碳又有新招。英國研究指出,肥料中常見的氨是取代貨輪柴油的最佳選擇,而且燃燒過程中並不會產生二氧化碳。對此,航運產業也希望能以氨取代柴油,幫助對抗氣候變遷。而最快在10年內,貨輪將可利用氨驅動。

    據《BBC》報導,英國皇家學會研究人員大衛表示,「氨是唯一能驅動貨輪航行各地零排碳的燃料。」研究也指出,製造氨雖會產生碳,但可透過新技術製造零碳的氨。首先是在製造時將二氧化碳捕捉並埋在地下,另一方法是利用再生能源製造氨。

    負責認證全球船隻的韓國船級社稍早也指出,由於氨作為燃料無須大量專門技術,因此是一種可行的潔淨能源。該組織在報告中指出,「氨的優勢在於相對容易存儲,因為與氫相比,前者具有合理能量、密度與液化溫度,與其他碳中性燃料相比,其生產與運輸成本也較低,並且已具備可穩定生產與運輸的技術。」

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※為什麼 USB CONNECTOR 是電子產業重要的元件?

    ※網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

    ※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

    ※想知道最厲害的台北網頁設計公司推薦、台中網頁設計公司推薦專業設計師”嚨底家”!!

    ※專營大陸快遞台灣服務

    ※台灣快遞大陸的貨運公司有哪些呢?

  • 氣候風險應納入企業稽核 全球會計師公會聯盟發起倡議

    環境資訊中心綜合外電;姜唯 編譯;林大利 審校

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

    ※評比前十大台北網頁設計、台北網站設計公司知名案例作品心得分享

    ※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

    ※台灣海運大陸貨務運送流程

    ※兩岸物流進出口一站式服務

  • 日311地震重災區 女川核電廠2號機通過重啟審查

    摘錄自2020年02月26日中央社報導

    日本女川核電廠2號機以重啟運轉為前提的申請,已通過日本原子力規制委員會審查,成為位於311大地震重災區首座合格的核電廠,也是第2座遭受海嘯侵襲重生的核電廠。

    日本放送協會(NHK)報導,東北電力公司希望位於宮城縣的女川核電廠2號機能重啟運轉提出申請,日本原子力規制委員會今(26日)已正式彙整完成表示合格的審查書。

    女川核電廠2號機是位於2011年311大地震後遭受重創的東北地方,首度獲審查合格的核電廠機組。東北電力公司在311大地震2年後的2013年,以重啟運轉為前提向原子力規制委員會提出審查申請。

    持續進行審議的原子力規制委員會,2019年11月彙整出表示事實上符合新規範標準的審查書草案,並向一般民眾徵集意見。

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包”嚨底家”

    ※網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

    ※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

    ※小三通海運與一般國際貿易有何不同?

    ※小三通快遞通關作業有哪些?

  • Spring註解@Configuration是如何被處理的?

    Spring註解@Configuration是如何被處理的?

    從SpringApplication開始

    一般情況下啟動SpringBoot都是新建一個類包含main方法,然後使用SpringApplication.run來啟動程序:

    @SpringBootApplication
    public class AutoConfigApplication {
    
        public static void main(String[] args){
            ConfigurableApplicationContext configurableApplicationContext = SpringApplication.run(AutoConfigApplication.class,args);
        }
    }
    

    SpringApplication.run接收兩個參數分別為:primarySource、運行參數(args),上面的代碼使用AutoConfigApplication.class作為primarySource。SpringApplication還有一個實例方法也叫run,SpringBoot的大部分啟動都由實例run方法來完成的,其中構造ApplicationContext由createApplicationContext方法完成:

    protected ConfigurableApplicationContext createApplicationContext() {
            Class<?> contextClass = this.applicationContextClass;
            if (contextClass == null) {
                try {
                    switch (this.webApplicationType) {
                    case SERVLET:
                        contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
                        break;
                    case REACTIVE:
                        contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                        break;
                    default:
                        contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
                    }
                }
                catch (ClassNotFoundException ex) {
                    throw new IllegalStateException(
                            "Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
                }
            }
            return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
        }

    createApplicationContext根據this.webApplicationType來構造ApplicationContext,不同的環境都會使用不同的實例,但本文非web環境所有構造的時候會使用AnnotationConfigApplicationContext類。創建AnnotationConfigApplicationContext的時候會調用默認構造方法:

    public AnnotationConfigApplicationContext() {
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

    AnnotationConfigApplicationContext默認構造函數創建兩個對象:

    • reader(AnnotatedBeanDefinitionReader):用於手動註冊bean
    • scanner(ClassPathBeanDefinitionScanner): 用於掃描Component、Repository、Service等註解

    AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner會註冊一些註解處理器,註冊的方式都是使用AnnotationConfigUtils的registerAnnotationConfigProcessors方法:

    public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
                BeanDefinitionRegistry registry, @Nullable Object source) {
    
            ...
            
            if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
                RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
                def.setSource(source);
                beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
            }
            ...
            return beanDefs;
        }

    最終AnnotationConfigApplicationContext構造方法執行完成后ApplicationContext會有以下BeanDefinition:

    構造完ApplicationContext后SpringApplicaiton緊接着會加載primarySource,上面提到 過primarySource是在運行的時候傳遞進來的(AutoConfigApplication.class),加載過程中不貼代碼了,只要知道最終ApplicaitonContext中會多一個AutoConfigApplication的BeanDefinition:

    小結

    總的來說SpringApplicaiton主要幹了這些事:

    • 創建AnnotationConfigApplicationContext
    • 加載一些處理註解的后處理器如:ConfigurationClassPostProcessor
    • 將primarySource加載進ApplicationContext

    最重要的一點是,現在是有一個AnnotationConfigApplicationContext裡面包含了primarySource(AutoConfigApplication)以及ConfigurationClassPostProcessor。打個斷點在ApplicaitonContext刷新之前打印下context中的bean的名稱,可以確定這樣說沒毛病!

    @Configuration啥時候被解析?

    雖說有了primarySource和ConfigurationClassPostProcessor后處理器,還是需要有個執行的入口。ConfigurationClassPostProcessor是BeanDefinitionRegistryPostProcessor的實現類,BeanDefinitionRegistryPostProcessor會在ApplicationContext的refresh操作時被處理:

    public void refresh() throws BeansException, IllegalStateException {
            synchronized (this.startupShutdownMonitor) {
                ...
                invokeBeanFactoryPostProcessors(beanFactory);
                ...
            }
    }
        
    public static void invokeBeanFactoryPostProcessors(
                ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
            
            ...
            //找出所有類型為BeanDefinitionRegistryPostProcessor的bean的名稱
            String[] postProcessorNames =
                        beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                }
            }
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            //執行BeanDefinitionRegistryPostProcessor
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            ...
    }
    
    private static void invokeBeanDefinitionRegistryPostProcessors(
            Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
    
        for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
            //調用postProcessBeanDefinitionRegistry方法
            postProcessor.postProcessBeanDefinitionRegistry(registry);
        }
    }   
    

    invokeBeanDefinitionRegistryPostProcessors會調用BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法,通過斷點調試工具確認下ConfigurationClassPostProcessor有沒有在這一步被處理:

    調試輸出postProcessors集合裏面有一個了ConfigurationClassPostProcessor元素,說明了ConfigurationClassPostProcessor的執行入口沒有問題。

    ConfigurationClassPostProcessor處理器

    ConfigurationClassPostProcessor首先會判斷在ApplicationContext中的bean是否被@Configuration註解標記,然後使用ConfigurationClassParser來解析@Configuration,ConfigurationClassPostProcessor的解析@Configuration的大致流程:

    1. 使用ConfigurationClassUtils.checkConfigurationClassCandidate檢查BeanDefinition是否@Configuration註解標記
    2. 對@Configuration進行排序
    3. 使用ConfigurationClassParser解析@Configuration註解的信息
    4. 使用ConfigurationClassBeanDefinitionReader解析BeanDefinition
    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
            List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
            
            //獲取所有BeanDefinitio名稱
            String[] candidateNames = registry.getBeanDefinitionNames();
            
            for (String beanName : candidateNames) {
                BeanDefinition beanDef = registry.getBeanDefinition(beanName);
                //如果是full、lite則說明已經處理過的類
                if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
                        ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
                    }
                }
                //檢查BeanDefinition是否有@Configuration註解
                else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
                    configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
                }
            }
    
            //如果沒有找到@Configuration標記的類,則返回不作處理也
            if (configCandidates.isEmpty()) {
                return;
            }
    
            //對@Configuration進行排序
            configCandidates.sort((bd1, bd2) -> {
                int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
                int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
                return Integer.compare(i1, i2);
            });
            
            ...
      
            ConfigurationClassParser parser = new ConfigurationClassParser(
                    this.metadataReaderFactory, this.problemReporter, this.environment,
                    this.resourceLoader, this.componentScanBeanNameGenerator, registry);
    
            Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
            Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
            do {
                //解析@Configuration class
                parser.parse(candidates);
                parser.validate();
    
                Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
                configClasses.removeAll(alreadyParsed);
    
                //讀取BeanDefinition
                if (this.reader == null) {
                    this.reader = new ConfigurationClassBeanDefinitionReader(
                            registry, this.sourceExtractor, this.resourceLoader, this.environment,
                            this.importBeanNameGenerator, parser.getImportRegistry());
                }
                this.reader.loadBeanDefinitions(configClasses);
                alreadyParsed.addAll(configClasses);
    
                candidates.clear();
                ...
            }
            while (!candidates.isEmpty());
            ...
        }

    最後還是通過調試工具看一下示例中的的啟動類AutoConfigApplication沒有被處理:

    圖上显示configCandidates中有一個名稱為autoConfigApplication的BeanDefinition的元素,說明AutoConfigApplication會被當作配置類解析,但是AutoConfigApplication並沒有使用@Configuration註解,為什麼還會被當做配置類呢?其實@Configuration在@SpringBootApplication註解中:

    紅色背景列出來的就是@Configuration註解,它是@SpringBootConfiguration的元註解。

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※帶您來了解什麼是 USB CONNECTOR  ?

    ※自行創業 缺乏曝光? 下一步”網站設計“幫您第一時間規劃公司的門面形象

    ※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

    ※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

    ※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

    ※試算大陸海運運費!

  • 談一談依賴倒置原則

    談一談依賴倒置原則

    為獲得良好的閱讀體驗,請訪問原文:

    一、概念

    依賴倒置原則(Dependence Inversion Principle,DIP)是指設計代碼結構時,高層模塊不應該依賴低層模塊,二者都應該依賴其抽象。

    抽象不應該依賴細節,細節應該依賴抽象。通過依賴倒置,可以減少類與類之間的耦合性,提高系統的穩定性,提高代碼的可讀性和可維護性,並且能夠降低修改程序所造成的風險。

    二、為什麼

    先來看一個例子

    可是依賴倒置原則是怎麼做到的呢?我們先來看一個例子:一個愛學習的「我沒有三顆心臟」同學現在正在學習「設計模式」和「Java」的課程,偽代碼如下:

    public class Wmyskxz {
    
        public void studyJavaCourse() {
            System.out.println("「我沒有三顆心臟」同學正在學習「Java」課程");
        }
    
        public void studyDesignPatternCourse() {
            System.out.println("「我沒有三顆心臟」同學正在學習「設計模式」課程");
        }
    }

    我們來模擬上層調用一下:

    public static void main(String[] args) {
        Wmyskxz wmyskxz = new Wmyskxz();
        wmyskxz.studyJavaCourse();
        wmyskxz.studyDesignPatternCourse();
    }

    原因一:有效控制影響範圍

    由於「我沒有三顆心臟」同學熱愛學習,隨着學習興趣的 “暴增”,可能會繼續學習 AI(人工智能)的課程。這個時候,因為「業務的擴展」,要從底層實現到高層調用依次地修改代碼。

    我們需要在 Wmyskxz 類中新增 studyAICourse() 方法,也需要在高層調用中增加調用,這樣一來,系統發布后,其實是非常不穩定的。顯然在這個簡單的例子中,我們還可以自信地認為,我們能 Hold 住這一次的修改帶來的影響,因為都是新增的代碼,我們回歸的時候也可以很好地 cover 住,但實際的情況和實際的軟件環境要複雜得多。

    最理想的情況就是,我們已經編寫好的代碼可以 “萬年不變”,這就意味着已經覆蓋的單元測試可以不用修改,已經存在的行為可以保證保持不變,這就意味着「穩定」。任何代碼上的修改帶來的影響都是有未知風險的,不論看上去多麼簡單。

    原因二:增強代碼可讀性和可維護性

    另外一點,你有沒有發現其實加上新增的 AI 課程的學習,他們三節課本質上行為都是一樣的,如果我們任由這樣行為近乎一樣的代碼在我們的類裏面肆意擴展的話,很快我們的類就會變得臃腫不堪,等到我們意識到不得不重構這個類以緩解這樣的情況的時候,或許成本已經變得高得可怕了。

    原因三:降低耦合

    《資本論》中有這樣一段描述:

    在商品經濟的萌芽時期,出現了物物交換。假設你要買一個 iPhone,賣 iPhone 的老闆讓你拿一頭豬跟他換,可是你並沒有養豬,你只會編程。所以你找到一位養豬戶,說給他做一個養豬的 APP 來換他一頭豬,他說換豬可以,但是得用一條金項鏈來換…

    所以這裏就出現了一連串的對象依賴,從而造成了嚴重的耦合災難。解決這個問題的最好的辦法就是,買賣雙發都依賴於抽象——也就是貨幣——來進行交換,這樣一來耦合度就大為降低了。

    三、怎麼做

    我們現在的代碼是上層直接依賴低層實現,現在我們需要定義一個抽象的 ICourse 接口,來對這種強依賴進行解耦(就像上面《資本論》中的例子那樣):

    接下來我們可以參考一下偽代碼,先定一個課程的抽象 ICourse 接口:

    public interface ICourse {
        void study();
    }

    然後編寫分別為 JavaCourse 和 DesignPatternCourse 編寫一個類:

    public class JavaCourse implements ICourse {
    
        @Override
        public void study() {
            System.out.println("「我沒有三顆心臟」同學正在學習「Java」課程");
        }
    }
    
    public class DesignPatternCourse implements ICourse {
    
        @Override
        public void study() {
            System.out.println("「我沒有三顆心臟」同學正在學習「設計模式」課程");
        }
    }

    然後把 Wmyskxz 類改造成如下的樣子:

    public class Wmyskxz {
    
        public void study(ICourse course) {
            course.study();
        }
    }

    再來是我們的調用:

    public static void main(String[] args) {
        Wmyskxz wmyskxz = new Wmyskxz();
        wmyskxz.study(new JavaCourse());
        wmyskxz.study(new DesignPatternCourse());
    }

    這時候我們再來看代碼,無論「我沒有三顆心臟」的興趣怎麼暴漲,對於新的課程,都只需要新建一個類,通過參數傳遞的方式告訴它,而不需要修改底層的代碼。實際上這有點像大家熟悉的依賴注入的方式了。

    總之,切記:以抽象為基準比以細節為基準搭建起來的架構要穩定得多,因此在拿到需求后,要面相接口編程,先頂層設計再細節地設計代碼結構。

    參考資料

    1. – 那些年搞不懂的高深術語——依賴倒置•控制反轉•依賴注入•面向接口編程
    2. 《Spring 5 核心原理 與 30 個類手寫實戰》 – 譚勇德 著

    按照慣例黏一個尾巴:

    歡迎轉載,轉載請註明出處!
    獨立域名博客:wmyskxz.com
    簡書ID:
    github:
    歡迎關注公眾微信號:wmyskxz
    分享自己的學習 & 學習資料 & 生活
    想要交流的朋友也可以加qq群:3382693
    錢

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
    【其他文章推薦】

    ※為什麼 USB CONNECTOR 是電子產業重要的元件?

    ※網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

    ※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

    ※想知道最厲害的台北網頁設計公司推薦、台中網頁設計公司推薦專業設計師”嚨底家”!!

    ※專營大陸快遞台灣服務

    ※台灣快遞大陸的貨運公司有哪些呢?