这一章我们将开始剖析Spring框架最为重要的AOP(Aspect Oriented Programming)面向切面编程。可以说Spring的精华就在于AOP了。
所谓AOP,就是相对于OOP(Object Oriented Programming)面向对象编程的说法,有些人喜欢叫面向切面编程,有些人喜欢叫做面向方面,事实上这两个都是指同一个东西,只是叫法不同。
我们传统的编程都是面向对象,就是说每个类都有它实际的意义。而面向切面略有不同,它在面向对象的基础上扩展了一下,它编程的时候不是先考虑的一个具体对象(比如用户类),而是先考虑的对象的行为或者功能。这个不是编程方法的不同,而是编程思维的转变。
理论性的东西还是放一边,我们用实际的机器人案例来慢慢理解这个概念。
为了突出重点我们这里重写了ISpeak:
package com.iteye.bolide74.impl;
public interface ISpeaker {
public void say(String msg);
}
接着是实现这个接口的机器人类:
package com.iteye.bolide74.action;
import com.iteye.bolide74.impl.ISpeaker;
public class Robot implements ISpeaker {
public String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Robot(String name) {
this.name = name;
}
@Override
public void say(String msg) {
System.out.println("到达邻居家,对邻居说:" + msg + ",我是" + this.name);
}
}
那么现在我们要实现跟很多个不同的邻居(不同的应用代码)打招呼,只需要下面的应用代码了:
package com.iteye.bolide74.tester;
import com.iteye.bolide74.action.Robot;
import com.iteye.bolide74.impl.ISpeaker;
public class Tester {
public static void main(String[] args) {
ISpeaker speaker = new Robot("Wall-E");
speaker.say("你好");
}
}
以上是实现最简单功能的方法。现在我们要慢慢增加功能了,假设Wall-E在出发打招呼之前要先拿一个礼物,然后打完招呼以后把礼物递给邻居,该怎么实现呢?
public void getGift() {
System.out.println("获取了一个礼物");
}
public void giveGift(){
System.out.println("赠予一个礼物");
}
最傻的办法就是每次在应用代码里调用speaker.say()方法的前后都调用get/give方法,小程序还好,要是大型程序的话人都要写傻掉。
那么能不能直接把get/give方法写在Robot类的say()方法里呢?这样好处是每次调用say()的时候都能实现get/give功能,但是坏处也是这个:万一有个别邻居是不需要给礼物的呢?怎么办?
那有没有更加灵活的办法呢?当然有!
代理模式:
我们先新建一个SpeakerProxy代理类:
package com.iteye.bolide74.action;
import com.iteye.bolide74.impl.ISpeaker;
public class SpeakerProxy implements ISpeaker {
ISpeaker speaker;
public SpeakerProxy(ISpeaker speaker) {
super();
this.speaker = speaker;
}
@Override
public void say(String msg) {
getGift();
speaker.say(msg);
giveGift();
}
public void getGift() {
System.out.println("获取了一个礼物");
}
public void giveGift(){
System.out.println("赠予一个礼物");
}
}
这个SpeakerProxy类实现了ISpeaker接口,然后又有一个靠构造函数传入的ISpeaker类型的成员属性。
而这个SpeakerProxy类的say()方法就有点意思了,它不是重写了自己的say()方法,而是调用了ISpeaker类型的speaker成员属性的say()方法,然后再这个say()方法前后嵌入get/give方法。
让我们看看这个SpeakerProxy类是怎么在应用代码使用:
package com.iteye.bolide74.tester;
import com.iteye.bolide74.action.Robot;
import com.iteye.bolide74.action.SpeakerProxy;
import com.iteye.bolide74.impl.ISpeaker;
public class SpeakerProxyTester {
public static void main(String[] arg0) {
// 没有带礼物的机器人:
ISpeaker noGiftSpeaker = new Robot("空手来的Wall-E");
noGiftSpeaker.say("你好");
System.out.println();
// 带了礼物的机器人
ISpeaker speaker = new SpeakerProxy(new Robot("有礼而来的Wall-E"));
speaker.say("你好");
}
}
输出结果:
引用
到达邻居家,对邻居说:你好,我是空手来的Wall-E
获取了一个礼物
到达邻居家,对邻居说:你好,我是有礼而来的Wall-E
赠予一个礼物
这样的话我们就达到了灵活性:不需要礼物的时候直接新建一个机器人;而需要礼物的时候我们就new一个SpeakerProxy(代理器),然后新建一个机器人丢进去,我们只要调用这个代理器就行了,这个代理器内部会给机器人一个礼物然后命令机器人去打招呼送礼物。
扩展阅读:装饰模式:
引用
装饰模式与AOP关系不大,但是它的实现方法与代理模式很像,不乘此机会一起介绍有点可惜,如果已经了解了装饰模式的可以直接跳过。
假设我们的机器人要送的礼物种类比较多,有红包、水果、花等等。而给不同的邻居打招呼送礼的时候都会送不同组合的礼物,比如:红包+水果、红包+花、水果+花、全部都送、单独送其中一样。
那么这种功能该怎么实现呢?每种组合写一个get/give方法吗?如果只有简单3种组合可能忍忍也就算了,但是如果以后礼物种类越来越多,那这个组合数量是成爆发性增长的,显然不合适。
那么这时候就该轮到装饰模式登场了:
package com.iteye.bolide74.action;
import com.iteye.bolide74.impl.ISpeaker;
public abstract class SpeakerGiftDecorator implements ISpeaker {
ISpeaker speaker;
public SpeakerGiftDecorator(ISpeaker speaker) {
super();
this.speaker = speaker;
}
public abstract void say(String msg);
public abstract void getGift();
public abstract void giveGift();
}
这是一个礼物的装饰器类,你可以理解为各种礼物的组装器。它的写法跟代理模式的代理类很像,不同的就是它是一个抽象类。它是所有种类的礼物的父类。
接下来就写一个继承了这个SpeakerGiftDecorator类的礼物之类:
package com.iteye.bolide74.action;
import com.iteye.bolide74.impl.ISpeaker;
//礼物的一种:一束花
public class Flower extends SpeakerGiftDecorator {
public Flower(ISpeaker speaker) {
super(speaker);
}
@Override
public void say(String msg) {
getGift();
this.speaker.say(msg);
giveGift();
}
@Override
public void getGift() {
System.out.println("获取了一束花");
}
@Override
public void giveGift() {
System.out.println("赠予一束花");
}
}
以上面的Flower子类类推来写出另外的Money类和Fruit类,区别仅在于get/give方法的内容不同,这里就不浪费篇幅了。
看起来代码似乎很简单,没什么出奇的,但是当应用代码使用的时候就能体现出它强大的地方了:
package com.iteye.bolide74.tester;
import com.iteye.bolide74.action.Flower;
import com.iteye.bolide74.action.Fruit;
import com.iteye.bolide74.action.Money;
import com.iteye.bolide74.action.Robot;
import com.iteye.bolide74.impl.ISpeaker;
public class SpeakerGiftDecoratorTester {
public static void main(String[] args) {
// 一种礼物:
ISpeaker speaker = new Flower(new Robot("我是带花来的Wall-E"));
speaker.say("Hello");
System.out.println();
// 两种礼物:
speaker = new Money(new Flower(new Robot("我是带了花和红包的Wall-E")));
speaker.say("Hello");
System.out.println();
// 另外两种礼物:
speaker = new Fruit(new Money(new Robot("我是带了水果和钱的Wall-E")));
speaker.say("Hello");
System.out.println();
// 三种礼物:
speaker = new Fruit(new Money(new Flower(new Robot("我是三种礼物都带的Wall-E"))));
speaker.say("Hello");
}
}
可以看到,speaker引用的是一个一层一层嵌套的类,要多带一种礼物那就多嵌套一层,这样就能尽可能的实现了代码的重用,而且应用起来也简单明了。
输出结果:
引用
获取了一束花
到达邻居家,对邻居说:Hello,我是我是带花来的Wall-E
赠予一束花
获取了一个红包
获取了一束花
到达邻居家,对邻居说:Hello,我是我是带了花和红包的Wall-E
赠予一束花
赠予一个红包
获取了一袋水果
获取了一个红包
到达邻居家,对邻居说:Hello,我是我是带了水果和钱的Wall-E
赠予一个红包
赠予一袋水果
获取了一袋水果
获取了一个红包
获取了一束花
到达邻居家,对邻居说:Hello,我是我是三种礼物都带的Wall-E
赠予一束花
赠予一个红包
赠予一袋水果
我的围脖:
http://t.qq.com/bolide74
下一篇:Spring温故知新(六)AOP面向切面编程 <2>
http://bolide74.iteye.com/blog/1007828
上一篇:Spring温故知新(五)Spring的Bean和IoC 容器
http://bolide74.iteye.com/blog/1004086
分享到:
相关推荐
SpringSpringSpring温故知新六AOP向切面程Spring温故知新六AOP向切面程
NULL 博文链接:https://bolide74.iteye.com/blog/1050199
备注:内容大部分从网上复制,代码为自己...<1>.比较相邻的元素。如果第一个比第二个大,就交换它们两个;<2>.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;<3>
CODESYS基础编程,详细的介绍了怎么使用CODESYS编程软件,适合初学者入门以及工程师温故知新。
spring cloud + openshift example
开始 这次的题目看上去好像有点奇怪:把两个没有什么关联的名词放在了一起,正如大家所知道的,transition-group就是Vue... // removeOnly is a special flag used only by <transition> // to ensure removed eleme
spring cloud config
常用的spring注解大全,适合新手学习、老手温故知新。读懂spring,平步青云。
温故知新ASP.NET 2.0(C#)温故知新ASP.NET 2.0(C#)温故知新ASP.NET 2.0(C#)温故知新ASP.NET 2.0(C#)温故知新ASP.NET 2.0(C#)
计算机小数表示.温故知新.pdf
数学:吃透课本温故知新.docx
大四学期复习Java基础所产生的代码笔记,着重回顾了字符串、IO、线程以及socket套接字编程,在每一分代码中都附带了自己编程时的一些认识、笔记。适合Java基础不够踏实的童鞋。
机械军工行业:“温故知新”系列之工业机器人行业复盘(二):从美国汽车行业“2mm工程”看工业机器人国产化空间.pdf
初中语文文学讨论现当代文学温故知新
6.1.4 何为“面向切面编程aop” 356 6.1.5 spring 2.5圣经——面向接口编程 358 6.1.6 开始spring 2.5旅程—hello world 359 6.2 spring 2.5核心技术 364 6.2.1 bean工厂之beanfactory介绍 364 6.2.2 实用的...
20210202-银河证券-“温故知新”系列之工业机器人行业复盘(二):从美国汽车行业“2mm工程”看工业机器人国产化空间.pdf
涵盖java基础,通俗易懂,适用于初学者及温故知新者
中信建设温故知新,从 4G 看 5G.rar
中信建设温故知新,从 4G 看 5G.pdf
图灵程序设计丛书:精通C#(第6版)是C#领域久负盛名的经典著作,深入全面地讲解了C#编程语言和。NET平台的核心内容,并结合大量示例剖析相关概念。全书分为八部分:C#和。NET平台、C#核心编程结构、C#面向对象编程...