摘要:但还有问题,这个类既控制了参数的输入,又控制了参数的输出。换句话说就是消息的输入和输出是耦合在一起的。进一步解耦让我们更进一步。接下来解耦消息的生产方。实际上,到这里已经完成了一个简易版的实现。
从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重构这部分只需要添加配置即可,略。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/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 进阶面试问题列表 -...
阅读 1474·2019-08-30 15:55
阅读 1175·2019-08-30 15:52
阅读 1292·2019-08-29 13:53
阅读 1467·2019-08-29 11:19
阅读 2974·2019-08-26 13:29
阅读 532·2019-08-26 11:33
阅读 2594·2019-08-23 17:20
阅读 1027·2019-08-23 14:14