什么是控制反转与依赖注入
控制反转IoC的英文全称是(“Inversion of Control”)。它使程序组件或类之间尽量形成一种松耦合的结构,开发者在使用类的实例之前,需要先创建对象的实例。但是IoC将创建实例的任务交给IoC容器,这样开发应用代码时只需要直接使用类的实例,这就是IoC控制反转。通常用一个所谓的好莱坞原则(“Don't call me. I will call you.”请不要给我打电话,我会打给你。)来比喻这种控制反转的关系。Martin Fowler曾专门写了一篇文章讨论控制反转这个概念,并提出一个更为准确的概念,叫做依赖注入(Dependency Injection,简称DI)。
【实例】使用Spring依赖注入的方式,开发一个打印机模拟程序。
实例要求:
(1)可以灵活地配置使用彩色墨盒还是灰色墨盒。
(2)可以灵活地配置打印页面的大小。
执行效果如下:
程序结构图:
程序中包括打印机(Printer)、墨盒(Ink)和纸张(IPaper)3个组件,打印机依赖墨盒和纸张。
(1)定义Ink墨盒接口和IPaper纸张接口。
package y2ssh.pjb.di.ink;
/**
* 墨盒接口
* @author pan_junbiao
**/
public interface Ink
{
public String getColor(int r,int g, int b);
}
package y2ssh.pjb.di.paper;
/**
* 纸张接口
* @author pan_junbiao
**/
public interface IPaper
{
public static final String newline = "\r\n";
/**
* 输出一个字符到纸张
*/
public void putInChar(char c);
/**
* 获取输出到纸张上的内容
*/
public String getContent();
}
(2)使用Ink接口和IPaper接口开发Printer类。
package y2ssh.pjb.di;
import y2ssh.pjb.di.ink.Ink;
import y2ssh.pjb.di.paper.IPaper;
/**
* 打印机程序
* @author pan_junbiao
**/
public class Printer
{
private Ink ink = null;
private IPaper paper = null;
public void print(String str)
{
//输出颜色标记
System.out.println("使用"+ink.getColor(255,200,0)+"颜色打印:");
//逐字符输出到纸张
for(int i=0; i<str.length(); i++)
{
paper.putInChar(str.charAt(i));
}
//将纸张的内容输出
System.out.println(paper.getContent());
}
public void setInk(Ink ink)
{
this.ink = ink;
}
public void setPaper(IPaper paper)
{
this.paper = paper;
}
}
Printer类只有一个print()方法,输入参数是一个即将被打印的字符串,打印机将这个字符串逐个字符输入到纸张,然后将纸张中的内容输出。
在开发Printer类程序的时候,我们只需要了解Ink接口和IPaper接口即可,完全不依赖这些接口的实现。
我们还需要提供“插槽”,以便组装的使用可以将Ink接口和IPaper接口的实例对象“注入”进来,对Java代码来说就是setter方法,代码中的setInk()方法和setPaper()方法。
(3)开发Ink接口和IPaper接口的实现类:ColorInk、GreyInk和TextPaper。
package y2ssh.pjb.di.ink;
import java.awt.Color;
/**
* 彩色墨盒
* @author pan_junbiao
**/
public class ColorInk implements Ink
{
public String getColor(int r,int g, int b)
{
Color color = new Color(r,g,b);
return "#" + Integer.toHexString(color.getRGB()).substring(2);
}
}
package y2ssh.pjb.di.ink;
import java.awt.Color;
/**
* 灰色墨盒
* @author pan_junbiao
**/
public class GreyInk implements Ink
{
public String getColor(int r,int g, int b)
{
int c = (r+g+b)/3;
Color color = new Color(c,c,c);
return "#" + Integer.toHexString(color.getRGB()).substring(2);
}
}
package y2ssh.pjb.di.paper;
/**
* 文本打印纸张实现
* @author pan_junbiao
**/
public class TextPaper implements IPaper
{
private String content = ""; //纸张中内容
private int charPerLine = 16; //每行字符数
private int linePerPage = 5; //每页行数
private int posX = 0; //当前横向位置,从0到charPerLine-1
private int posY = 0; //当前行数,linePerPage-1
private int posP = 1; //当前页数
//Setter方法,用于属性注入
public void setCharPerLine(int charPerLine)
{
this.charPerLine = charPerLine;
}
public void setLinePerPage(int linePerPage)
{
this.linePerPage = linePerPage;
}
public void putInChar(char c)
{
content += c;
++posX;
//判断是否换行
if (posX == charPerLine)
{
content += IPaper.newline;
posX = 0;
++posY;
}
//判断是否翻页
if (posY == linePerPage)
{
content += "== 第" + posP + "页 ==";
content += IPaper.newline + IPaper.newline;
posY = 0;
++ posP;
}
}
public String getContent()
{
return this.content;
}
}
(4)组装打印机(Spring依赖注入)
在项目中添加Spring的jar包和commons-logging.jar文件。
在src目录下创建applicationContext.xml配置文件。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<!-- Spring配置文件 -->
<beans>
<bean id="colorInk" class="y2ssh.pjb.di.ink.ColorInk"/>
<bean id="greyInk" class="y2ssh.pjb.di.ink.GreyInk"/>
<bean id="a4Paper" class="y2ssh.pjb.di.paper.TextPaper">
<property name="charPerLine" value="160"/>
<property name="linePerPage" value="8"/>
</bean>
<bean id="b5Paper" class="y2ssh.pjb.di.paper.TextPaper">
<property name="charPerLine" value="90"/>
<property name="linePerPage" value="5"/>
</bean>
<!-- 组装一台彩色的、使用B5打印纸的打印机 -->
<bean id="printer_color_b5" class="y2ssh.pjb.di.Printer">
<property name="ink" ref="colorInk"/>
<property name="paper" ref="b5Paper"/>
</bean>
<!-- 组装一台灰色的、使用A4打印纸的打印机 -->
<bean id="printer_grey_a4" class="y2ssh.pjb.di.Printer">
<property name="ink" ref="greyInk"/>
<property name="paper" ref="a4Paper"/>
</bean>
</beans>
(5)运行测试
package y2ssh.pjb.di;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 运行测试
* @author pan_junbiao
**/
public class DITest
{
public static void main(String[] args)
{
//装载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//获取printer实例(彩色的、使用B5打印纸的打印机)
Printer colorPrinter = (Printer)context.getBean("printer_color_b5");
String str = "您好,欢迎访问 pan_junbiao的博客!\n" +
"博客地址:https://blog.csdn.net/pan_junbiao\n" +
"岁月从来不曾静好,只是有人在替你背负枷锁,含泪前行。也许是父母,也许是朋友,也许是陌生人,无论是谁,请记得常怀感恩之心。";
colorPrinter.print(str);
}
}