从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.HelloWorldMessageRendererconsumer.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重构
这部分只需要添加配置即可,略。