控制反转(IoC)
public interface Service1 {
void execute();
}
public class Service1Impl implements Service1 {
private Service2 service2;
public Service1Impl(Service2 service2) {
this.service2 = service2;
}
@Override
public void execute() {
System.out.println("Service1 is doing something.");
service2.execute();
}
}
public interface Service2 {
void execute();
}
public class Service2Impl implements Service2 {
@Override
public void execute() {
System.out.println("Service2 is doing something.");
}
}
// 工厂类的实现
public class Service2Factory {
public static Service2 getService2Instance() {
return new Service2Impl();
}
}
public class Service1Factory {
public static Service1 getService1Instance() {
Service2 service2 = Service2Factory.getService2Instance();
return new Service1Impl(service2);
}
}
// 测试代码
public class Client {
public void doSomething() {
Service1 service = Service1Factory.getService1Instance();
service.execute();
}
}
-- Service1 is doing something.
-- Service2 is doing something.
- 工厂类泛滥:在实际应用中,经常出现几百个像这样的服务类,如果使用工厂方法模式的话,就可能出现几百个这样的工厂类。因为不知道将来会产生多少子类扩展系统,所以也不能使用静态工厂模式。
- 依赖关系复杂:往往这几百个 Service对象之间存在复杂的依赖关系,工厂类的装配逻辑也随之变得十分复杂。增加了装配这些服务对象的精力,而不能专注于业务功能的开发。
- 不易进行单元测试。
Inversion of Control(控制反转):
- 模板方法模式——父类的模板方法控制子类的方法调用
- 回调的方法也是控制反转的很好应用。
- 在 Java标准库里,查找(binarySearch) 和 排序(sort)这两个方法,他们在执行过程中会调用对象的 compareTo( ) 方法(如果这些对象实现了 java.lang.Comparable 接口的话),或者调用我们所传递的回调接口 java.util.Comparator 对象的 compare( ) 方法来比较大小,最终完成查找/排序操作。
- 框架:框架抽象了通用流程,我们可以通过框架提供的规范(如子类化抽象类或者实现相关的接口,实现相关的交互协议和接口等)就可以把客户化的代码植入流程中,完成各种定制的需求。
- Service Locator(服务定位器)
- Dependency Injection(依赖注入,简写为 DI)
//简单的服务定位器
public class ServiceLocator {
private static ServiceLocator locator;
// 创建 HashMap<String, Object>对象来持有这些服务对象
private Map<String, Object> services = new HashMap<String, Object>(); // 初始化容器
public static void configure() {
load(new ServiceLocator()); // Service1、Service2的对象其实是按照单例创建的
Service2 service2 = new Service2Impl();
locator.services.put("service2", service2);
Service1 service1 = new Service1Impl(service2);
locator.services.put("service1", service1);
} private static void load(ServiceLocator serviceLocator) {
locator = serviceLocator;
} public static Object lookup(String serviceName) {
return locator.services.get(serviceName);
} public static void registerService(String name, Object service) {
locator.services.put(name, service);
}
}
public class Client {
public void doSomething() {
Service1 service1 = (Service1) ServiceLocator.lookup("service1");
service1.execute();
}
// 测试代码
public static void main(String[] args) {
// 初始化容器
ServiceLocator.configure();
new Client().doSomething();
}
}
- Setter 注入:外部程序通过调用 setting方法为客户对象注入所依赖的对象。(Spring框架是使用反射机制调用 setting方法注入依赖的对象)
- Constructor 注入:通过带参数的构造方法注入依赖对象。
- Annotation 注入:把实例化信息和对象之间的依赖关系信息使用 Annotation注解。
- Interface 注入:客户程序通过实现容器/框架所规范的某些特殊接口,在为客户对象返回这些依赖的对象之前,容器回调这些接口的方法,注入所依赖的服务对象。如:Struts2中的 Action实现了接口 ServletRequesetAware、SessionAware等,只要 Action类实现这些接口,Struts框架就会调用这些接口的相应方法,注入 HttpServletRequest、HttpSession对象。
- Parameter 注入 :外部程序可以通过函数参数,给客户程序注入所依赖的服务对象。
- 其它形式的注入
// ServiceAware 接口
public interface ServiceAware {
void injectService(Service service);
}
// Service 接口及其实现类
public interface Service {
void excute();
}
public class ServiceImpl implements Service { @Override
public void excute() {
System.out.println("Service is doing something...");
} } // 创建简单的接口注入容器
public class InterfaceInjector { private static InterfaceInjector injector;
private Map<Class, Object> services = new HashMap<Class, Object>(); // 安装容器
public static void configure() {
load(new InterfaceInjector());
} public static <T> T getInstance(Class<T> clazz) {
return injector.loadService(clazz);
} private static void load(InterfaceInjector container) {
InterfaceInjector.injector = container; } private <T> T loadService(Class<T> clazz) { Object service = injector.services.get(clazz); if (service != null) {
return (T) service;
} try {
// 创建 clazz类实例
service = clazz.newInstance();
// 通过接口装配依赖的对象,如果对象是 ServiceAware的实例为真
if (service instanceof ServiceAware) {
// 则调用此接口的方法注入 ServiceAware对象
((ServiceAware) service).injectService(new ServiceImpl());
}
injector.services.put(clazz, service);
} catch (Exception e) {
e.printStackTrace();
} return (T) service;
} } // 只要服务类实现这个接口,容器就会注入 Service对象,定义一个 Client类实现该接口
public class Client implements ServiceAware { private Service service; @Override
public void injectService(Service service) {
this.service = service;
} public void doSomething() {
service.excute();
} public static void main(String[] args) {
InterfaceInjector.configure();
Client client = InterfaceInjector.getInstance(Client.class);
client.doSomething();
}
}
-- Service is doing something...
//参数注入
public class Client {
// 外部程序通过函数参数,给客户程序注入所依赖的服务对象
// 采用外部传递 Service对象方式,至于Service如何实例化,它一无所知
public void dosomething(Service service) {
service.excute();
} // 使用方法:外部程序实例化一个 Service实例,传递给 Client的 dosomething(Service service)方法使用
public static void main(String[] args) {
Service service = new ServiceImpl();
new Client().dosomething(service);
}
}
- IoC使得客户专注于客户化的逻辑设计,把程序流程的控制交给外部代码,实现高内聚低耦合目标。
- 把实例化的过程交给框架/容器来处理,使得我们更专注于业务逻辑的开发。
控制反转(IoC)的更多相关文章
- 控制反转IoC简介
控制反转IoC简介 在实际的应用开发中,我们需要尽量避免和降低对象间的依赖关系,即降低耦合度.通常的业务对象之间都是互相依赖的,业务对象与业务对象.业务对象与持久层.业务对象与各种资源之间都存在这样或 ...
- 浅析“依赖注入(DI)/控制反转(IOC)”的实现思路
开始学习Spring的时候,对依赖注入(DI)——也叫控制反转(IOC)—— 的理解不是很深刻.随着学习的深入,也逐渐有了自己的认识,在此记录,也希望能帮助其他入门同学更深入地理解Spring.本文不 ...
- 控制反转IOC的依赖注入方式
引言: 项目中遇到关于IOC的一些内容,因为和正常的逻辑代码比较起来,IOC有点反常.因此本文记录IOC的一些基础知识,并附有相应的简单实例,而在实际项目中再复杂的应用也只是在基本应用的基础上扩展而来 ...
- 控制反转IOC与依赖注入DI
理解 IOC http://www.cnblogs.com/zhangchenliang/archive/2013/01/08/2850970.html IOC 相关实例 的http:// ...
- 控制反转(Ioc)和依赖注入(DI)
控制反转IOC, 全称 “Inversion of Control”.依赖注入DI, 全称 “Dependency Injection”. 面向的问题:软件开发中,为了降低模块间.类间的耦合度,提倡基 ...
- 控制反转IOC与依赖注入DI【转】
转自:http://my.oschina.net/1pei/blog/492601 一直对控制反转.依赖注入不太明白,看到这篇文章感觉有点懂了,介绍的很详细. 1. IoC理论的背景我们都知道,在采用 ...
- 依赖注入(DI)和控制反转(IOC)
依赖注入(DI)和控制反转(IOC) 0X1 什么是依赖注入 依赖注入(Dependency Injection),是这样一个过程:某客户类只依赖于服务类的一个接口,而不依赖于具体服务类,所以客户类只 ...
- iOS控制反转(IoC)与依赖注入(DI)的实现
背景 最近接触了一段时间的SpringMVC,对其控制反转(IoC)和依赖注入(DI)印象深刻,此后便一直在思考如何使用OC语言较好的实现这两个功能.Java语言自带的注解特性为IoC和DI带来了极大 ...
- 个人对【依赖倒置(DIP)】、【控制反转(IOC)】、【依赖注入(DI)】浅显理解
一.依赖倒置(Dependency Inversion Principle) 依赖倒置是面向对象设计领域的一种软件设计原则.(其他的设计原则还有:单一职责原则.开放封闭原则.里式替换原则.接口分离原则 ...
- 【转载】浅析依赖倒置(DIP)、控制反转(IOC)和依赖注入(DI)
原文地址 http://blog.csdn.net/briblue/article/details/75093382 写这篇文章的原因是这两天在编写关于 Dagger2 主题的博文时,花了大量的精力来 ...
随机推荐
- Awk中调用shell命令
Awk中调用shell命令 需求 在awk中,有时候需要调用linux系统中命令,如计算字符串的MD5值,并保存下来. 方法参考 call a shell command from inside aw ...
- spring mvc中的valid
当你希望在spring mvc中直接校验表单参数时,你可以采用如下操作: 声明Validator的方式: 1.为每一个Controller声明一个Validator @Controller publi ...
- keil中如何得知所编译程序所占空间大小?
keil编译后出现Program Size: data=21.0 xdata=0 code=2231. 这表明 data= 21.0 数据储存器内部RAM占用21字节, xdata=0 数据 ...
- 【转贴】Linux系统NGINX负载均衡404错误处理方法
NGINX负载均衡404错误处理方法 使用NGINX 实现负载均衡,但一组服务器的数据不是实施同步,主服务器有了数据要过段时间才同步到其他服务器 upstream image.stream.com ...
- hdu 1171 Big Event in HDU(多重背包+二进制优化)
题目链接:hdu1171 思路:将多重背包转为成完全背包和01背包问题,转化为01背包是用二进制思想,即件数amount用分解成若干个件数的集合,这里面数字可以组合成任意小于等于amount的件数 比 ...
- Openfire开发配置,Openfire源代码配置,OpenFire二次开发配置(eclipse)
首先去官网把openfire的源码下下来: http://www.igniterealtime.org/downloads/source.jsp 1.下载后放到你的workspace当中,我的woek ...
- Visual Studio无法添加断点
今天在写代码的时候突然发现无法添加断点,更加详细的场景是“按F9可以添加调试行,但是断点不显示,且显示代码行数左边的灰色区域不见了”找了各种方法也没有解决,然后重启.修复甚至重装都不行,最后在万千网页 ...
- jquery实现的个性网站首页 详细信息
http://download.csdn.net/detail/a757956132/9305419 实现效果: 1:导航效果(兼容IE) 2:网站换肤 3:模块展开和关闭 4:新闻滚动 5:超链接文 ...
- iOS开发-UIColor转UIIamge方法
只能说太神奇了,完美应用到我的毕业设计 - (UIImage*) createImageWithColor: (UIColor*) color { CGRect rect=CGRectMake(,,s ...
- WPF中的ControlTemplate(控件模板)(转)
原文地址 http://www.cnblogs.com/zhouyinhui/archive/2007/03/28/690993.html WPF中的ControlTemplate(控件模板) ...