摘要:但還有問題,這個類既控制了參數的輸入,又控制了參數的輸出。換句話說就是消息的輸入和輸出是耦合在一起的。進一步解耦讓我們更進一步。接下來解耦消息的生產方。實際上,到這里已經完成了一個簡易版的實現。
從Hello world開始
先上一段代碼:
public class HelloWorldTest { public static void main(String[] args) { System.out.println("Hello world!"); } }
這是Java里面最簡單的一段代碼了,做的事情非常簡單:控制臺打印出“Hello world!”字符串。很明顯,這段代碼很不好拓展,假如我們想打印別的內容呢?
第一步改動OK,接下來做一點簡單的改動:
public class HelloWorldTest { public static void main(String[] args) { if (args.length > 0) { System.out.println(args[0]); } else { System.out.println("Hello world!"); } } }
這樣當我們運行帶參數時,控制臺會輸出我們的第一個參數。這樣我們就取得了第一個小小的進步:我們可以不修改代碼就控制了不同的輸出。但還有問題,這個類既控制了參數的輸入,又控制了參數的輸出。換句話說就是:消息的輸入和輸出是耦合在一起的。
進一步解耦讓我們更進一步。首先我們添加一個獲取消息的類:
public class MessageConsumer { public String sayHello(String message) { if (Objects.isNull(message) || message.length() < 1) { return "Hello world!"; } return message; } }
這樣當輸入的參數不為null或者空字符串時,輸出參數,否則輸出Hello world!。調用方只需要在調用的時候傳入不同的參數,就達到了輸出不同內容的目的。OK,現在已經解耦了消息的輸出方,但生產方還在main方法里。接下來解耦消息的生產方。添加一個新的類來生產消息:
public class MessageRenderer { private MessageConsumer messageConsumer; public void render(){ if (Objects.isNull(messageConsumer)){ System.out.println("Hello world!"); }else { System.out.println(messageConsumer.sayHello("MessageRenderer")); } } public MessageConsumer getMessageConsumer() { return messageConsumer; } public void setMessageConsumer(MessageConsumer messageConsumer) { this.messageConsumer = messageConsumer; } }
這樣主函數只需要new出MessageRenderer和MessageConsumer對象即可,對于消息怎么生產和消費則不需要關心。但這樣的問題是MessageRender和MessageConsumer耦合在一起。
面向接口我們更進一步對兩個類進行抽象:
public interface MessageConsumer { String sayHello(String message); }
public interface MessageRenderer { void render(); MessageConsumer getMessageConsumer(); void setMessageConsumer(MessageConsumer messageConsumer); }
新建實現類:
public class HelloWorldMessageConsumer implements MessageConsumer { @Override public String sayHello(String message) { return message; } }
public class HelloWorldMessageRenderer implements MessageRenderer { private MessageConsumer messageConsumer; @Override public void render() { if (Objects.isNull(messageConsumer)) { System.out.println("Hello world!"); } else { System.out.println(messageConsumer.sayHello("HelloWorldMessageRenderer")); } } @Override public MessageConsumer getMessageConsumer() { return messageConsumer; } @Override public void setMessageConsumer(MessageConsumer messageConsumer) { this.messageConsumer = messageConsumer; } }
程序入口:
public class HelloWorldTest { public static void main(String[] args) { MessageRenderer renderer = new HelloWorldMessageRenderer(); MessageConsumer consumer = new HelloWorldMessageConsumer(); renderer.setMessageConsumer(consumer); renderer.render(); } }
至此,消息的生產和消費解耦開來,生產方只依賴消費方的抽象而不是具體實現,主程序只負責new出需要的生產方和消費方即可。三者的關系如如:
運行程序我們可以得到我們想要的輸出內容,但還有一點小問題:我們現在要的是HelloWorldMessageConsumer,假如我們需要別的MessageConsumer呢?那就需要改主程序代碼了。
簡易版IOC下面我們添加一個類來生產MessageConsumer和MessageRenderer:
public class MessageSupportFactory { private static MessageSupportFactory instance; private Properties properties; private MessageRenderer messageRenderer; private MessageConsumer messageConsumer; static { instance = new MessageSupportFactory(); } public static MessageSupportFactory getInstance() { return instance; } private MessageSupportFactory() { properties = new Properties(); try { properties.load(this.getClass().getResourceAsStream("/msf.properties")); String rendererClass = properties.getProperty("renderer.class"); String consumerClass = properties.getProperty("consumer.class"); messageRenderer = (MessageRenderer) Class.forName(rendererClass).newInstance(); messageConsumer = (MessageConsumer) Class.forName(consumerClass).newInstance(); } catch (Exception e) { e.printStackTrace(); } } public MessageRenderer getMessageRenderer() { return messageRenderer; } public MessageConsumer getMessageConsumer() { return messageConsumer; } }
msg.properties代碼如下:
renderer.class=org.chunrun.learn.sp.message.HelloWorldMessageRenderer consumer.class=org.chunrun.learn.sp.message.HelloWorldMessageConsumer
主程序代碼如下:
public class HelloWorldTest { public static void main(String[] args) { MessageConsumer consumer = MessageSupportFactory.getInstance().getMessageConsumer(); MessageRenderer renderer = MessageSupportFactory.getInstance().getMessageRenderer(); renderer.setMessageConsumer(consumer); renderer.render(); } }
這樣,當我們需要不同的MessageRenderer或MessageConsumer時,只需要在配置文件里指定不同的對象即可。實際上,到這里已經完成了一個簡易版的IOC實現。
使用Spring重構這部分只需要添加配置即可,略。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/69273.html
摘要:框架最初是由編寫的,并且年月首次在許可下發布。在一個方法執行之后,只有在方法退出拋出異常時,才能執行通知在建議方法調用之前和之后,執行通知。方法執行之后,不考慮其結果,執行通知。 導讀: 在上篇文章的結尾提到了Spring Boot 提供了一系列的框架整合(Starter POMs)幫助我們提升開發效率,但是這并不意味著我們不需要學習這些框架,反而更需要去學習,通過學習這些框架可以使...
摘要:簡介為了寫容器源碼分析系列的文章,我特地寫了一篇容器的導讀文章。在做完必要的準備工作后,從本文開始,正式開始進入源碼分析的階段。從緩存中獲取單例。返回以上就是和兩個方法的分析。 1. 簡介 為了寫 Spring IOC 容器源碼分析系列的文章,我特地寫了一篇 Spring IOC 容器的導讀文章。在導讀一文中,我介紹了 Spring 的一些特性以及閱讀 Spring 源碼的一些建議。在...
摘要:今天來學習一包導入在官網下載開發包然后導入需要的包到項目目錄下。 今天來學習Spring ioc . 一、spring jar 包導入 在 spring 官網下載開發包 spring-framework-4.2.4.RELEASE,然后導入需要的 jar 包到項目 /lib/ 目錄下。 ?showImg(https://segmentfault.com/img/bVbbiyW?w=34...
摘要:本文是容器源碼分析系列文章的第一篇文章,將會著重介紹的一些使用方法和特性,為后續的源碼分析文章做鋪墊。我們可以通過這兩個別名獲取到這個實例,比如下面的測試代碼測試結果如下本小節,我們來了解一下這個特性。 1. 簡介 Spring 是一個輕量級的企業級應用開發框架,于 2004 年由 Rod Johnson 發布了 1.0 版本。經過十幾年的迭代,現在的 Spring 框架已經非常成熟了...
摘要:從使用到原理學習線程池關于線程池的使用,及原理分析分析角度新穎面向切面編程的基本用法基于注解的實現在軟件開發中,分散于應用中多出的功能被稱為橫切關注點如事務安全緩存等。 Java 程序媛手把手教你設計模式中的撩妹神技 -- 上篇 遇一人白首,擇一城終老,是多么美好的人生境界,她和他歷經風雨慢慢變老,回首走過的點點滴滴,依然清楚的記得當初愛情萌芽的模樣…… Java 進階面試問題列表 -...
閱讀 1470·2019-08-30 15:55
閱讀 1172·2019-08-30 15:52
閱讀 1282·2019-08-29 13:53
閱讀 1465·2019-08-29 11:19
閱讀 2964·2019-08-26 13:29
閱讀 527·2019-08-26 11:33
閱讀 2587·2019-08-23 17:20
閱讀 1022·2019-08-23 14:14