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