你真的了解Ioc与AOP吗?

作为一个应用系统,代码复用至关重要。如果在你的设计中,类与类存在很强的相互关联,那么你会发现在重用这些组件时就存在很严重的问题。在 Step1到Step3-Reflection的例子中,我们试图 利用“针对接口编程”以及自己设计的Ioc对系统进行解耦。在Step3到Step5的例子中,我们将利用Spring.net提供的Ioc框架,轻松完 成解耦以及系统改造等工作。

一、类之间的依赖

我们的第一个例子主要用于说明程序的基本构造,并且作为一个反面典型,引出为什么要解耦,以及如何下手。在这个例子中,我们将创建三个程序集,分别是MainApp.exe、HelloGenerator.dll以及SayHello.dll。它们之间的关系如下图所示:

 

 

 


 

 

 

HelloGenerator类根据提供的姓名产生一个问候字符串,代码如下:

using System;

namespace IocInCSharp

{

public class EnHelloGenerator

{

public string GetHelloString(string name)

{

return String.Format("Hello, {0}", name);

}

}

}







SayHello类持有一个对EnHelloGenerator的引用,并负责将生成出来的问候字符串打印出来。

using System;

namespace IocInCSharp

{

public class SayHello

{

private EnHelloGenerator _helloGen;

public EnHelloGenerator HelloGenerator

{

get { return _helloGen; }

set { _helloGen = value; }

}

public void SayHelloTo(string name)

{

if(_helloGen != null)

Console.WriteLine(_helloGen.GetHelloString(name));

else

Console.WriteLine("Client.hello is not initialized");

}

}

}





MainApp.exe负责完成对象的创建、组装以及调用工作:

using System;

namespace IocInCSharp

{

public class MainApp

{

public static void Main()

{

SayHello sayHello = new SayHello();

sayHello.HelloGenerator = new EnHelloGenerator();

sayHello.SayHelloTo("zhenyulu");

}

}

}





在这个设计中,组件与组件之间、类与类之间存在着紧密的耦合关系。SayHello类中的_helloGen字段类型为 EnHelloGenerator,这将导致我们很难给它赋予一个其它的HelloGenerator(例如CnHelloGenerator,用于生成 中文问候语)。另外MainApp也严重依赖于SayHello.dll以及HelloGenerator.dll,在程序中我们可以看到类似new SayHello();new EnHelloGenerator();的命令。

这种紧密的耦合关系导致组件的复用性降低。试想,如果想复用SayHello组件,那么我们不得不连同HelloGenerator一同拷贝过去, 因为SayHello.dll是依赖与HelloGenerator.dll的。解决这个问题的办法就是“针对抽象(接口)”编程 (依赖倒置原则)。这里的抽象既包括抽象类也包括接口。我不想过多的去谈抽象类和接口的区别,在后续的例子中我们将使用接口。由于接口在进行“动态代理” 时仍能保持类型信息,而抽象类可能由于代理的原因导致继承关系的“截断”(如MixIn等)。除此之外,对于单继承的C#语言而言,使用接口可以拥有更大 的弹性。

二、接口依赖

既然类之间的依赖导致耦合过于紧密,按照《设计模式》的理论,我们要依赖于接口。但是人们往往发现,仅仅依赖于接口似乎并不能完全解决问题。我们从上面的例子中抽象出接口后,组件间的依赖关系可能变成如下图所示:

 

 

 


 

 

 

经过改造后,SayHello不再依赖于具体的HelloGenerator,而是依赖于IHelloGenerator接口,如此一来,我们可以 动态的将EnHelloGenerator或是CnHelloGenerator赋给SayHello,其打印行为也随之发生改变。接口的定义以及改造后 的SayHello代码如下(为了节省空间,将代码合并书写):

using System;

namespace IocInCSharp

{

public interface IHelloGenerator

{

string GetHelloString(string name);

}

public interface ISayHello

{

IHelloGenerator HelloGenerator{ get; set; }

void SayHelloTo(string name);

}

public class SayHello : ISayHello

{

private IHelloGenerator _helloGen;

public IHelloGenerator HelloGenerator

{

get { return _helloGen; }

set { _helloGen = value; }

}

public void SayHelloTo(string name)

{

if(_helloGen != null)

Console.WriteLine(_helloGen.GetHelloString(name));

else

Console.WriteLine("Client.hello is not initialized");

}

}

}





但是我们的MainApp似乎并没有从接口抽象中得到什么好处,从图中看,MainApp居然依赖于三个组件:ICommon.dll、 HelloGenerator.dll以及SayHello.dll。这是由于MainApp在这里负责整体的“装配”工作。如果这三个组件中的任何一个 发生变化,都将导致MainApp.exe的重新编译和部署。从这个角度来看,似乎“针对接口编程”并没有为我们带来太多的好处。

如果能够将“组件装配”工作抽象出来,我们就可以将MainApp的复杂依赖关系加以简化,从而 进一步实现解耦。为此,我们引入“工厂”模式,并利用配置文件和反射技术,动态加载和装配相关组件。

 

(未完,请参考来源)

来源:http://www.cnblogs.com/zhenyulu/zhenyulu/articles/233966.html

<think>好的,我需要回答用户关于IOCAOP的概念、原理、区别和联系的问题。首先,我得回忆一下相关的知识,并结合提供的引用内容来组织答案。 首先,IOC,也就是控制反转,是Spring的核心之一。根据引用[1]和[4],IOC的主要思想是将对象的创建和依赖关系的管理从程序内部转移到第三方容器。这样做的目的是降低耦合度,提高灵活性。用户提到控制反转的具体实现是依赖注入(DI),或者有人认为DI是IoC的一种实现方式。这点需要明确,可能需要指出不同的观点。 接下来是AOP,面向切面编程。引用[2]和[3]详细说明了AOP的基本概念,比如连接点、切入点、通知等。AOP用于处理横切关注点,如日志、事务等,这些功能分散在多个地方,通过AOP可以模块化处理,避免代码冗余。需要解释AOP的原理,比如动态代理,以及它在Spring中的实现方式,比如JDK动态代理和CGLIB,引用[3]提到了这些内容。 然后,关于两者的区别和联系。IOC主要负责对象的管理和依赖注入,而AOP处理横切关注点。它们的应用场景不同,但都属于Spring的核心机制,共同提升代码的可维护性和扩展性。需要指出它们如何协同工作,比如在IOC管理的对象上应用AOP的切面。 在结构上,用户希望答案分点清晰,可能需要分为概念、原理、区别、联系几个部分。每个部分引用相应的引用内容,比如在解释IOC时引用[1]和[4],AOP引用[2]和[3]。要注意引用标识的正确添加,比如在提到控制反转时引用[^1][^4],AOP的基本概念引用[^2][^3]。 可能还需要检查是否有遗漏的知识点,比如IOC的其他实现方式,或者AOP的织入过程。确保覆盖用户的问题,包括原理、区别和联系,而不仅仅是概念。 最后,生成相关问题,可能需要围绕IOCAOP的应用、具体实现方式、优缺点等方面提问。例如,如何实现依赖注入,或者AOP在实际项目中的使用案例。 现在需要把这些思考整理成一个结构清晰的中文回答,正确使用引用,并确保LaTeX格式符合要求,比如行内公式用$...$,独立公式用$$...$$。不过当前问题可能不需要数学公式,但如果有相关例子可能需要添加。例如,如果讨论AOP的切入点表达式,可能需要使用LaTeX,但根据用户的问题,可能不涉及数学表达式,所以可能不需要。不过要确保其他格式正确,比如代码块使用反引号,引用标识正确放置。 总结一下,回答的结构应该是: 1. 概念 - IOC - AOP 2. 原理 - IOC的实现(DI) - AOP的动态代理 3. 区别 - 关注点不同 - 实现方式不同 4. 联系 - 共同目标 - 协同工作 5. 相关问题 每个部分引用相应的内容,例如在IOC概念部分引用[^1],在AOP原理部分引用[^3]等。确保每个引用标识自然出现在句末,不重复使用同一引用多次,除非必要。 现在开始撰写正式的回答,确保符合所有格式要求,使用中文,分点清晰,引用正确。</think>### 一、IOC(控制反转)AOP(面向切面编程)的概念及原理 #### 1. **IOC(控制反转)** - **概念** **控制反转(IoC)** 是一种设计思想,其核心是将对象的创建和依赖关系的控制权从程序代码中转移到外部容器(如Spring框架)。在传统编程中,对象直接通过`new`关键字创建并管理依赖,而IoC通过第三方(容器)统一管理对象生命周期和依赖注入(DI)。例如,类A依赖类B时,不再由A主动创建B,而是由容器将B注入到A中[^4]。 - **原理** IoC通过**依赖注入**实现,常见方式包括构造器注入、Setter方法注入和接口注入。Spring容器负责读取配置(XML或注解),创建对象并建立依赖关系。这种机制降低了代码耦合度,提升了可维护性和扩展性。 #### 2. **AOP(面向切面编程)** - **概念** **面向切面编程(AOP)** 是对面向对象编程(OOP)的补充,用于处理**横切关注点**(如日志、事务、权限等)。这些功能分散在多个模块中,AOP通过动态织入代码的方式将其模块化,避免代码冗余[^2][^3]。 - **原理** AOP基于**动态代理**技术实现,主要步骤如下: 1. **定义切面(Aspect)**:包含通知(Advice)和切入点(Pointcut)。 2. **织入(Weaving)**:在目标对象的方法执行前后插入增强逻辑。 3. **代理生成**:Spring通过JDK动态代理(接口)或CGLIB(类)创建代理对象,实现对目标对象的增强。 ### 二、IOCAOP的区别联系 #### 1. **区别** | **维度** | **IOC** | **AOP** | |----------------|----------------------------------|----------------------------------| | **关注点** | 对象创建依赖管理 | 横切关注点的模块化 | | **实现方式** | 依赖注入(DI) | 动态代理、反射 | | **应用场景** | 解耦对象间的直接依赖 | 日志、事务、权限等公共功能 | #### 2. **联系** - **共同目标**:提升代码的可维护性和扩展性。IOC通过解耦对象依赖,AOP通过分离横切逻辑,两者协同降低系统复杂度。 - **协同工作**:在Spring中,IOC容器管理的对象是AOP的**目标对象**。AOP通过代理机制增强这些对象的功能,例如事务管理依赖于IOC注入的数据源。 ### 三、示例说明 - **IOC示例**: ```java // 传统方式:由类A主动创建B class A { private B b = new B(); } // IOC方式:由容器注入B @Component class A { @Autowired private B b; } ``` - **AOP示例**(记录方法执行时间): ```java @Aspect public class LogAspect { @Around("execution(* com.example.service.*.*(..))") public Object logTime(ProceedingJoinPoint joinPoint) throws Throwable { long start = System.currentTimeMillis(); Object result = joinPoint.proceed(); System.out.println("耗时:" + (System.currentTimeMillis() - start) + "ms"); return result; } } ``` ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值