新闻中心
扫一扫,分享内容
打赏作者
GeorgiaStar
你的鼓励将是我创作的最大动力
您的余额不足,请更换扫码支付或
抵扣说明:
1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。
Copyright © 2022 BlackMagic#
Ioc模式与工厂模式比较
2010-03-26 来源:网络
分离关注( Separation of Concerns : SOC)是Ioc模式和AOP产生最原始动力,通过功能分解可得到关注点,这些关注可以是 组件Components, 方面Aspects或服务Services。
从GoF设计模式中,我们已经习惯一种思维编程方式:Interface Driven Design 接口驱动,接口驱动有很多好处,可以提供不同灵活的子类实现,增加代码稳定和健壮性等等,但是接口一定是需要实现的,也就是如下语句迟早要执行:
AInterface a = new AInterfaceImp();
AInterfaceImp是接口AInterface的一个子类,Ioc模式可以延缓接口的实现,根据需要实现,有个比喻:接口如同空的模型套,在必要时,需要向模型套注射石膏,这样才能成为一个模型实体,因此,我们将人为控制接口的实现成为“注射”。
Ioc英文为 Inversion of Control,即反转模式,这里有著名的好莱坞理论:你呆着别动,到时我会找你。后被Martin Fowler改名为 Dependency Injection 依赖注射,也就是将类之间的关系通过第三方进行注射,不需要类自己去解决调用关系。
其实Ioc模式也是解决调用者和被调用者之间的一种关系,上述AInterface实现语句表明当前是在调用被调用者AInterfaceImp,由于被调用者名称写入了调用者的代码中,这产生了一个接口实现的原罪:彼此联系,调用者和被调用者有紧密联系,在UML中是用依赖 Dependency 表示。
但是这种依赖在分离关注的思维下是不可忍耐的,必须切割,实现调用者和被调用者解耦,新的Ioc模式 Dependency Injection 模式由此产生了, Dependency Injection模式是依赖注射的意思,也就是将依赖先剥离,然后在适当时候再注射进入。
Ioc模式(Dependency Injection模式)有三种:
有过EJB开发经验的人都知道,每个EJB的调用都需要通过JNDI寻找到工厂性质的Home接口,在我的教程
章节中,我也是从依赖和工厂模式角度来阐述EJB的使用。
在通常传统情况下,为了实现调用者和被调用者解耦,分离,一般是通过工厂模式实现的,下面将通过比较工厂模式和Ioc模式不同,加深理解Ioc模式。
假设有两个类B 和 C:B作为调用者,C是被调用者,在B代码中存在对C的调用:
实现comp实例有两种途径:单态工厂模式和Ioc。
工厂模式实现如下:
public B(){
this.comp = myFactory.createInstanceOfC();
}
public void someMethod(){
this.comp.sayHello();
}
......
}
特点:
使用Ioc依赖性注射( Dependency Injection )实现Picocontainer如下,B类如同通常POJO类,如下:
假设C接口/类有有一个具体实现CImp类。当客户端调用B时,使用下列代码:
因此,当客户端调用B时,分别使用工厂模式和Ioc有不同的特点和区别:
主要区别体现在B类的代码,如果使用Ioc,在B类代码中将不需要嵌入任何工厂模式等的代码,因为这些工厂模式其实还是与C有些间接的联系,这样,使用Ioc彻底解耦了B和C之间的联系。
使用Ioc带来的代价是:需要在客户端或其它某处进行B和C之间联系的组装。
所以,Ioc并没有消除B和C之间这样的联系,只是转移了这种联系。
这种联系转移实际也是一种分离关注,它的影响巨大,它提供了AOP实现的可能。
AOP我们已经知道是一种面向切面的编程方式,由于Ioc解放自由了B类,而且可以向B类实现注射C类具体实现,如果把B类想像成运行时的横向动作,无疑注入C类子类就是AOP中的一种Advice,如下图:
通过下列代码说明如何使用Picocontainer实现AOP,该例程主要实现是记录logger功能,通过Picocontainer可以使用简单一行,使所有的应用类的记录功能激活。
首先编制一个记录接口:
public void enableLogging(Log log);
}
有一个LogSwitcher类,主要用来激活具体应用中的记录功能:
一般的普通应用JavaBeans都可以继承这个类,假设PicoUserManager是一个用户管理类,代码如下:
..... //用户管理功能
}
public class PicoXXXX1Manager extends LogSwitcher
{
..... //业务功能
}
public class PicoXXXX2Manager extends LogSwitcher
{
..... //业务功能
}
注意LogSwitcher中Log实例是由外界赋予的,也就是说即将被外界注射进入,下面看看使用Picocontainer是如何注射Log的具体实例的。
Logging logging = (Logging) container.getComponentMulticaster();
logging.enableLogging(new SimpleLog("pico"));//激活log
由上代码可见,通过使用简单一行logging.enableLogging()方法使所有的应用类的记录功能激活。这是不是类似AOP的advice实现?
总之,使用Ioc模式,可以不管将来具体实现,完全在一个抽象层次进行描述和技术架构,因此,Ioc模式可以为容器、框架之类的软件实现提供了具体的实现手段,属于架构技术中一种重要的模式应用。J道的
使用了Ioc模式,
是一个IOC/DI成熟应用。
|
|
转载自:http://www.cnblogs.com/DebugLZQ/archive/2013/06/05/3107957.html
https://segmentfault.com/a/1190000014803412
1.IOC的理论背景
2.什么是IOC
3.IOC也叫依赖注入(DI)
4.IOC的优缺点
5.IOC容器的技术剖析
6.IOC容器的一些产品
7.参考博文
本文旨在用语言(非代码)说清楚IOC到底是什么,没有什么高深的技术,园中的老牛、大虾们看到这里可以绕行了,以免浪费您宝贵的时间。IOC这个东西DebugLZQ早就想写了,但是出于对文章权威性的考虑(不能误人子弟- -!),本文主要内容来源于最近LZ看的一些国内外的关于IOC的博文、博问,所有引用到的文章,在
中均已注明。
我们知道在面向对象设计的软件系统中,它的底层都是由N个对象构成的,各个对象之间通过相互合作,最终实现系统地业务逻辑[1]。
图1 软件系统中耦合的对象
如果我们打开机械式手表的后盖,就会看到与上面类似的情形,各个齿轮分别带动时针、分针和秒针顺时针旋转,从而在表盘上产生正确的时间。图1中描述的就是这样的一个齿轮组,它拥有多个独立的齿轮,这些齿轮相互啮合在一起,协同工作,共同完成某项任务。我们可以看到,在这样的齿轮组中,如果有一个齿轮出了问题,就可能会影响到整个齿轮组的正常运转。
齿轮组中齿轮之间的啮合关系,与软件系统中对象之间的耦合关系非常相似。对象之间的耦合关系是无法避免的,也是必要的,这是协同工作的基础。现在,伴随着工业级应用的规模越来越庞大,对象之间的依赖关系也越来越复杂,经常会出现对象之间的多重依赖性关系,因此,架构师和设计师对于系统的分析和设计,将面临更大的挑战。对象之间耦合度过高的系统,必然会出现牵一发而动全身的情形。
图2 对象之间的依赖关系
耦合关系不仅会出现在对象与对象之间,也会出现在软件系统的各模块之间,以及软件系统和硬件系统之间。如何降低系统之间、模块之间和对象之间的耦合度,是软件工程永远追求的目标之一。为了解决对象之间的耦合度过高的问题,软件专家Michael Mattson 1996年提出了IOC理论,用来实现对象之间的“解耦”,目前这个理论已经被成功地应用到实践当中。
IOC是Inversion of Control的缩写,多数书籍翻译成“控制反转”。
1996年,Michael Mattson在一篇有关探讨面向对象框架的文章中,首先提出了IOC 这个概念。对于面向对象设计及编程的基本思想,前面我们已经讲了很多了,不再赘述,简单来说就是把复杂系统分解成相互合作的对象,这些对象类通过封装以后,内部实现对外部是透明的,从而降低了解决问题的复杂度,而且可以灵活地被重用和扩展。
如下图:
图3 IOC解耦过程
大家看到了吧,由于引进了中间位置的“第三方”,也就是IOC容器,使得A、B、C、D这4个对象没有了耦合关系,齿轮之间的传动全部依靠“第三方”了,全部对象的控制权全部上缴给“第三方”IOC容器,所以,IOC容器成了整个系统的关键核心,它起到了一种类似“粘合剂”的作用,把系统中的所有对象粘合在一起发挥作用,如果没有这个“粘合剂”,对象与对象之间会彼此失去联系,这就是有人把IOC容器比喻成“粘合剂”的由来。
我们再来做个试验:把上图中间的IOC容器拿掉,然后再来看看这套系统:
图4 拿掉IOC容器后的系统
我们现在看到的画面,就是我们要实现整个系统所需要完成的全部内容。这时候,A、B、C、D这4个对象之间已经没有了耦合关系,彼此毫无联系,这样的话,当你在实现A的时候,根本无须再去考虑B、C和D了,对象之间的依赖关系已经降低到了最低程度。所以,如果真能实现IOC容器,对于系统开发而言,这将是一件多么美好的事情,参与开发的每一成员只要实现自己的类就可以了,跟别人没有任何关系!
我们再来看看,控制反转(IOC)到底为什么要起这么个名字?我们来对比一下:
软件系统在没有引入IOC容器之前,如图1所示,对象A依赖于对象B,那么对象A在初始化或者运行到某一点的时候,自己必须主动去创建对象B或者使用已经创建的对象B。无论是创建还是使用对象B,控制权都在自己手上。
软件系统在引入IOC容器之后,这种情形就完全改变了,如图3所示,由于IOC容器的加入,对象A与对象B之间失去了直接联系,所以,当对象A运行到需要对象B的时候,IOC容器会主动创建一个对象B注入到对象A需要的地方。
通过前后的对比,我们不难看出来:
2004年,Martin Fowler探讨了同一个问题,
控制被反转之后,获得依赖对象的过程由自身管理变为了由IOC容器主动注入。于是,他给“控制反转”取了一个更合适的名字叫做“依赖注入(Dependency Injection)”。他的这个答案,实际上给出了实现IOC的方法:注入。
所以,依赖注入(DI)和控制反转(IOC)是从不同的角度的描述的同一件事情,就是指通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦。
学过IOC的人可能都看过Martin Fowler(老马,2004年post)的这篇文章:Inversion of Control Containers and the Dependency Injection pattern[2]。
博客园的园友EagleFish(邢瑜琨)的文章:
[3]对老马那篇经典文章进行了解读。
CSDN黄忠成的
[4]也是,不过他应该来自台湾省,用的是繁体,看不管繁体中文的,可以看园中的吕震宇博友的简体中文版
[5] 。
In my experience, IoC using the Spring container brought the following advantages[6]:
使用IOC框架产品能够给我们的开发过程带来很大的好处,但是也要充分认识引入IOC框架的缺点,做到心中有数,杜绝滥用框架[1]。
第一、软件系统中由于引入了第三方IOC容器,生成对象的步骤变得有些复杂,本来是两者之间的事情,又凭空多出一道手续,所以,我们在刚开始使用IOC框架的时候,会感觉系统变得不太直观。所以,引入了一个全新的框架,就会增加团队成员学习和认识的培训成本,并且在以后的运行维护中,还得让新加入者具备同样的知识体系。
第二、由于IOC容器生成对象是通过反射方式,在运行效率上有一定的损耗。如果你要追求运行效率的话,就必须对此进行权衡。
第三、具体到IOC框架产品(比如:Spring)来讲,需要进行大量的配制工作,比较繁琐,对于一些小的项目而言,客观上也可能加大一些工作成本。
第四、IOC框架产品本身的成熟度需要进行评估,如果引入一个不成熟的IOC框架产品,那么会影响到整个项目,所以这也是一个隐性的风险。
我们大体可以得出这样的结论:一些工作量不大的项目或者产品,不太适合使用IOC框架产品。另外,如果团队成员的知识能力欠缺,对于IOC框架产品缺乏深入的理解,也不要贸然引入。最后,特别强调运行效率的项目或者产品,也不太适合引入IOC框架产品,像WEB2.0网站就是这种情况。
,目前.Net C#、Java和PHP5等语言均支持,其中PHP5的技术书籍中,有时候也被翻译成“映射”。有关反射的概念和用法,大家应该都很清楚,通俗来讲就是根据给出的类名(字符串方式)来动态地生成对象。这种编程方式可以让对象在生成时才决定到底是哪一种对象。反射的应用是很广泛的,很多的成熟的框架,比如象Java中的Hibernate、Spring框架,.Net中 NHibernate、Spring.Net框架都是把“反射”做为最基本的技术手段。
Sun ONE技术体系下的IOC容器有:轻量级的有Spring、Guice、Pico Container、Avalon、HiveMind;重量级的有EJB;不轻不重的有JBoss,Jdon等等。Spring框架作为Java开发中SSH(Struts、Spring、Hibernate)三剑客之一,大中小项目中都有使用,非常成熟,应用广泛,EJB在关键性的工业级项目中也被使用,比如某些电信业务。
.Net技术体系下的IOC容器有:Spring.Net、Castle等等。Spring.Net是从Java的Spring移植过来的IOC容器,Castle的IOC容器就是Windsor部分。它们均是轻量级的框架,比较成熟,其中Spring.Net已经被广泛应用于各种项目中。
总之就是很多很多,不甚枚举.....
[1]
---IoC框架 ,王泽宾,CSDN, 2009.
[2]
,Martin Fowler,2004.
[3]
,EagleFish(邢瑜琨), 博客园, 2007.
[4]
,黄忠成, CSDN, 2006.
[5]
,吕震宇,博客园, 2006.
[6]
扫一扫,分享内容
抵扣说明:
1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。
6.7w+
社区成员
22.5w+
社区内容
致力于权威的科学传播
西南大学
|
|
京ICP证030173号-1 京网文【2013】0934-983号 ©2022Baidu
|
整理了半天的文档,就知道AOP是面向切面编程降低耦合度的。求大神解答
个人理解
IOC:控制反转(DI依赖注入),将以前由我们自己手动创建对象的过程交给了Spring,Spring帮助我们生产对象、管理对象、管理对象和对象之间的依赖关系。降低了代码的耦合度,方便我们后期对项目做维护。
三种注入方式:
1.setter注入
2.构造器注入
3.属性注入(注解)
@Autowired:默认根据类型进行匹配
@Resource:首先根据名称进行匹配,再根据类型进行匹配
自动装配autowire属性
AOP:面向切面(方便)编程,可以为某一类对象 进行监督和控制,也就是在调用这类对象的具体方法的前后去调用你指定的功能模块,从而达到对一个模块扩充的功能。可以通过注解或者XML文档进行实现。
开发切面,切面里面写的功能模块,叫做通知。
前置通知@Before、后置通知@AfterReturning、最终通知@After、异常通知@AfterThrowing、环绕通知@Around
后置通知和最终通知的区别:
后置通知只有在方法正常执行后才会被调用,如果方法执行过程中报错,则不会执行后置通知,而是执行异常通知。
无论方法执行有没有报错,都会执行最终通知
AOP最重要的一个应用:Spring的事务管理器。
Spring的事务管理器就是一个切面,切面中的功能不再是计算时间、输出日志,而是管理事务。因为Spring的事务管理器要对一组数据库操作做事务控制。所以事务管理器需要切入到一个可以包含所有Dao操作的方法中,即Service方法。
Spring事务管理器的特点:所有的事务,要么同时提交,要么同时回滚。只要有一次失误失败,所有事务一起回滚。
JDBC事务的特点:每执行完一次数据库操作就提交一次事务。
报告相同问题?
1 背景介绍
spring是什么?
一个为了解决企业应用开发的复杂性而创建的开源框架,一个轻量级的控制反转(IOC)面向切面(AOP)的容器框架
2 知识剖析
spring中的IOC是什么意思?
spring通过IOC即反转控制促进了松耦合,一个对象依赖的其他对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖的对象
为什么要使用IOC而不是new来创建实例?
调用者直接使用new创建被调用者的实例,两者之间的耦合度很高
要由调用者亲自创建被调用者的实例对象,不利于软件的移植与维护
3 常见问题
IOC有哪些缺点?
创建对象的步骤变复杂了
通过反射来创建对象,会造成效率上的损耗
缺少IDE重构的支持,如果修改了类名还需要到XML文件中手动修改
4 解决方案
相比IOC的灵活性和可维护性来说,这点缺点可以忍受
5 编码实战
一个配置文件
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
class="com.StudentJDBCTemplate">
负责实现的主函数(进行了创建和修改两种操作)
package com;
import java.util.List;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.StudentJDBCTemplate;
public class MainApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
StudentJDBCTemplate studentJDBCTemplate = (StudentJDBCTemplate)context.getBean("studentJDBCTemplate");
System.out.println("Records Creation");
studentJDBCTemplate.create("韩",12);
// List students = studentJDBCTemplate.listStudents();
// for (Student record:students) {
// System.out.println("ID:" + record.getId());
// System.out.println(", Name : " + record.getName());
// }
System.out.println("update start");
studentJDBCTemplate.update(12,"韩大师");
// studentJDBCTemplate.delete(12);
}
}
JDBCTemplate
package com;
import java.util.List;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
public class StudentJDBCTemplate implements StudentDAO{
private DataSource dataSource;
private JdbcTemplate jdbcTemplateObject;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.jdbcTemplateObject = new JdbcTemplate(dataSource);
}
public void create(String name,Integer ID) {
String SQL = "insert into student (name,ID) values (?,?)";
jdbcTemplateObject.update(SQL,name,ID);
return;
}
// @Override
// public Student getStudent(Integer ID) {
// String SQL = "select * from student where id = ?";
// Student student = jdbcTemplateObject.query(SQL,new Object[]{ID}, new StudentMapper());
// return student;
// }
@Override
public List listStudents() {
String SQL = "select * from student";
List students = jdbcTemplateObject.query(SQL,new StudentMapper());
return students;
}
@Override
public void delete(Integer ID) {
String SQL = "delete from student where ID = ?";
jdbcTemplateObject.update(SQL,ID);
System.out.println("Deleted Record with ID =" + ID);
return;
}
@Override
public void update(Integer ID, String name) {
String SQL = "update student set name = ? where ID = ?";
jdbcTemplateObject.update(SQL,name,ID);
System.out.println("Updated Record with ID = "+ ID);
return;
}
}
6 扩展思考
spring控制反转是控制什么反转
IOC控制反转,强调容器的作用,用于组织或控制容器内bean的运行,把传统上有程序代码直接操控的对象的调用权交给容器
7 参考文献
w3cschool spring 概述
百度
8 更多讨论
什么是bean?
由IOC容器管理的那些组成应用程序的对象就是bean,是由spring容器初始化,装配以及管理的对象。
9 提问
spring的依赖注入有什么优势?
spring的依赖注入有四种方式:Setter方法注入;构造方法注入;静态工厂的方法注入;实例工厂的方法注入
让使用者不需要自己去创建或获取自己的依赖,既然创建或获取的过程不是使用者控制的,这也就意味着,当我需要切换依赖时,不需要改变使用者的代码
@Autowired和@Resource的区别?
@Autowired 默认按类型装配
依赖对象必须存在,如果要允许null值,可以设置它的required属性为false @Autowired(required=false)
也可以使用名称装配,配合@Qualifier注解
@Resource 默认按名称进行装配,通过name属性进行指定
大白话解释,@Autowired自动注解,举个例子吧,一个类,俩个实现类,Autowired就不知道注入哪一个实现类,而Resource有name属性,可以区分。
By Type和 By Name的区别?
byName 通过参数名 自动装配,如果一个bean的name 和另外一个bean的 property 相同,就自动装配。
byType 通过参数的数据类型自动自动装配,如果一个bean的数据类型和另外一个bean的property属性的数据类型兼容,就自动装配
spring注入bean的方式有哪些?
首先要配置被注入的bean,在该bean对应的类中,应该有要注入的对象属性或者基本数据类型的属性。
UserBiz类注入UserDAO,同时为UserBiz注入基本数据类型String,那么这时,就要为UserDAO对象和String类型设置setter方法.,用于进行依赖注入。
如何配置该bean呢?
userDao
第一,在PersonBiz类中注入PersonDAO和一个String类型的数据;在该类中,不用为PersonDAO属性和String数据类型的属性设置setter方法,但是需要生成该类的构造方法;
第二,在配置文件中配置该类的bean,并配置构造器,在配置构造器中用到了节点,该节点有四个属性:
· index是索引,指定注入的属性,从0开始,如:0代表personDao,1代表str属性;
· type是指该属性所对应的类型,如Persondao对应的是com.aptech.dao.PersonDAO;
· ref 是指引用的依赖对象;
· value 当注入的不是依赖对象,而是基本数据类型时,就用value;