聊聊模板方法模式,装饰器模式以及AOP
在软件系统设计的时候,我们需要把一个大的系统按照业务功能进行拆分,做到高内聚、低耦合。
但是呢,拆分之后会产生一些通用性的东西,比如日志,安全,事务,性能统计等,这些非功能性需求,横跨多个模块。最low的一种写法如下:
public class PlaceOrderCommand {
public void execute(){
//记录日志
logger.debug("...");
//性能统计
PerformaceUtil.startTimer(...);
//权限检查
if(!user.hasPreviledge(...)){
抛异常
}
//开始事务
beginTransaction();
//真正的业务代码
commitTransaction();
PerformanceUtil.endTimer(...);
logger.debug("...");
}
}
为什么说上面这种方式low呢,主要是因为它把日志、安全、事务、性能统计这些非业务相关的代码和业务代码完全耦合在了一起,每个类都得这么写,徒劳无功,繁琐重复。
1. 模板方法模式
由此引入一种牛逼的处理方式,叫做模板方法模式。在父类中将乱七八糟的非功能性代码写好,子类去实现相应的抽象方法就好啦。
public abstract class BaseCommand{
public void execute(){
//记录日志
logger.debug("...");
//性能统计
PerformaceUtil.startTimer(...);
//权限检查
if(!user.hasPreviledge(...)){
抛异常
}
//开始事务
beginTransaction();
//真正的业务代码
doBusiness();
commitTransaction();
PerformanceUtil.endTimer(...);
logger.debug("...");
}
public abstract void doBusiness();
}
class PlaceOrderCommand extends BaseCommand {
@Override
public void doBusiness() {
//下单操作
}
}
class PaymentCommand extends BaseCommand {
@Override
public void doBusiness() {
//执行支付操作
}
}
//执行代码
BaseCommand command = new PlaceOrderCommand();
cmd.execute();
子类只需要关注业务逻辑就好啦,是不是很清爽?
但是这也有问题,就是我把非业务功能写了一大坨,我要是想分开描述,比如安全啊,事务啊,日志啊,我不想写在一起,就比较麻烦。我可以写多个抽象类,但是Java又是单类继承。而且,这样父类会定义一切,子类只能无条件接受,制约性比较大,比如有个子类不想加日志了,就没办法了。
2. 装饰器模式
由此引入更牛逼的一种设计模式,装饰器模式。它牛逼在可以灵活地自定义执行次序。
public interface Command {
public void execute();
}
//记录日志的装饰器
class LoggerDec implements Command {
Command cmd;
public LoggerDec(Command cmd) {
this.cmd = cmd;
}
@Override
public void execute(){
//记录日志
logger.debug("...");
//真正的业务代码
this.cmd.execute();
logger.debug("...");
}
}
//性能统计的装饰器
class PerformanceDec implements Command {
Command cmd;
public PerformanceDec(Command cmd) {
this.cmd = cmd;
}
@Override
public void execute(){
PerformaceUtil.startTimer(...);
//真正的业务代码
this.cmd.execute();
PerformanceUtil.endTimer(...);
}
}
class PlaceOrderCommand implements Command {
@Override
public void execute() {
//下单操作
}
}
class PaymentCommand implements Command {
@Override
public void execute() {
//支付操作
}
}
//执行代码
Command command = new LoggerDec(new PerformanceDec(new PlaceOrderCommand()));
command.execute();
可以随意更改包裹的内容,即代码中的红色区域,更改顺序啊,加一个减一个啊等等,灵活不已。
但是也有一些问题,就是处理日志、安全、事务、性能统计的类为啥要实现业务接口(Command)呢?这在道理上面说不通啊。还有就是,没有实现业务接口,也想实现非业务功能,那应该怎么办呢?
3. AOP
AOP是Spring框架中很牛逼的一个组成,另外一个是IoC。把非功能性代码和业务代码完全隔离开来,让其正交。
把业务代码看成面包,那么非功能性代码就是一个个切面,方便灵活切入,这就是面向切面编程。
定义一个切面类,就是一个普通类。
public class Transaction {
public void begin(){
//开始事务
}
public void commit(){
//提交事务
}
}
定义一个切入点,就是com.nonfunction包下面的所有类的execute()方法。
定义一个通知,就是在方法调用之前执行啊,还是在方法调用之后执行啊。
我们想做的就是,对于com.nonfunction包下面的所有类的execute()方法,在调用之前执行开始事务的方法,在调用之后执行提交事务的方法。
这里以XML隔离为例(建议用注解的方式):
<bean id="tx" class="com.nonfunction.Transaction" />
<aop:config>
<aop:aspect id="txAspect" ref="tx">
<aop:pointcut id="placeorder" expression="execution(public * com.nonfunction.*.execute(..))"/>
<aop:before method="begin" pointcut-ref="placeorder"/>
<aop:after method="commit" pointcut-ref="placeorder"/>
</aop:aspect>
</aop:config>
以上的方式,便可以达到完全的隔离。
但是呢,由于Java是静态强类型语言,编译成Java类以后,运行时通过反射可以查看类的信息,但是对编译好的类进行修改是不可能的。
咋办?
第一种方式就是修改现有类,在编译的时候把非功能性代码和业务代码编译到一起,这样改变业务类了,扑街。
第二种方式生成代理类,这也是用的最多的,让代理类变成增强类,原来的业务类不用改变,客户操作的是代理类对象。
那么怎么生成代理类呢,一种是使用Java自己的动态代理技术,一种是CGLib。
参考我的这篇博客吧:https://www.cnblogs.com/DarrenChan/p/9958421.html
所谓的Spring容器,就是帮你生成一个代理类,我们给它要对象,它就给你生成一个代理对象,但是我们不知道啊,还以为是原来业务类的对象。

聊聊模板方法模式,装饰器模式以及AOP的更多相关文章
- Python3-设计模式-装饰器模式
装饰器模式 动态的给原有对象添加一些额外的职责,面向切面编程(AOP),多用于和主业务无关,但又必须的业务,如:登录认证.加锁.权限检查等 Python代码实现示例 需求点: 1.在old_func( ...
- Decorator模式 装饰器模式
Android 使用了装饰器模式 1. 概述 若你从事过面向对象开发,实现给一个类或对象增加行为,使用继承机制,这是所有面向对象语言的一个基本特性.如果已经存在的一个类缺少某些方法,或者须要给方法添加 ...
- Python设计模式-装饰器模式
装饰器模式 装饰器模式,动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式比生成子类更为灵活. 代码示例 #coding:utf-8 #装饰器模式 class Beverage(): ...
- Java设计模式12:装饰器模式
装饰器模式 装饰器模式又称为包装(Wrapper)模式.装饰器模式以多客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 装饰器模式的结构 通常给对象添加功能,要么直接修改对象添加相应的功能, ...
- IOS设计模式之二(门面模式,装饰器模式)
本文原文请见:http://www.raywenderlich.com/46988/ios-design-patterns. 由 @krq_tiger(http://weibo.com/xmuzyq) ...
- Java IO流以及装饰器模式在其上的运用
流概述 Java中,流是一种有序的字节序列,可以有任意的长度.从应用流向目的地称为输出流,从目的地流向应用称为输入流. Java的流族谱 Java的 java.io 包中囊括了整个流的家族,输出流和输 ...
- python设计模式之装饰器模式
装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰 ...
- java设计模式之 装饰器模式
装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构. 这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装 ...
- java IO之 字符流 (字符流 = 字节流 + 编码表) 装饰器模式
字符流 计算机并不区分二进制文件与文本文件.所有的文件都是以二进制形式来存储的,因此, 从本质上说,所有的文件都是二进制文件.所以字符流是建立在字节流之上的,它能够提供字符 层次的编码和解码.列如,在 ...
- JAVA设计模式--装饰器模式
装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰 ...
随机推荐
- SQL 查询 技巧
一.使用SELECT检索数据 数据查询是SQL语言的中心内容,SELECT 语句的作用是让数据库服务器根据客户要求检索出所需要的信息资料,并按照规定的格式进行整理,返回给客户端. SELECT 语句的 ...
- 正则表达式(特殊字符)/Xpath语法/CSS选择器
正则表达式(特殊字符) ^ 开头 '^b.*'----以b开头的任意字符 $ 结尾 '^b.*3$'----以b开头,3结尾的任意字符 * 任意长度(次数),≥0 ? 非贪婪模式,非贪婪模式尽可能少的 ...
- boost 1.67编译VS2017版本
最近想系统学习并使用一下boost的asio异步网络库,所以需要编译boost库使用,下面简单介绍如何编译. 编译环境 boost1.67版本,windows 10,VS2017 下载boost 建议 ...
- ASP.net的总结(一:理论理解)
概述 这篇博客和之前博客有些重复的部分,如果要详细了解相应部分内容,可以到相应连接博客中查看.本篇博客主要介绍了什么是ASP.net,ASP.net在浏览器和服务器端的交互过程,ASP.net服务器端 ...
- ASP.NET Core中使用Razor视图引擎渲染视图为字符串(转)
一.视图渲染说明 在有些项目需求上或许需要根据模板生产静态页面,那么你一样可以用Razor语法去直接解析你的页面从而把解析的页面生成静态页,这样的使用场景很多,不限于生成静态页面,视图引擎为我们提供了 ...
- 从入门到精通Puppet的实践之路
本文有感于<精通Puppet配置管理工具>在豆瓣上的某些差评而顺手写的书评. 半路出家 故事要从12年初说起. 某天,部门老大让我所在team的老大调研一下当下业界的配置管理工具.于 ...
- Java 8 学习资料汇总【转载】
原文地址 2014年3月18日,Java SE 8 发布,而 Java 9 预期2016年发布: 2011年7月7日,Java 7 发布,是2009年4月20日被Oracle 以74亿美元收购首次推出 ...
- 微软BI 之SSIS 系列 - 导出数据到 Excel 2013 的实现
开篇介绍 碰到有几个朋友问到这个问题,比较共性,就特意写了这篇小文章说明一下如何实现在 SSIS 中导出数据到 Office Excel 2013 中.通常情况下 2013 以前的版本大多没有问题,但 ...
- angularjs drag and drop
angular-dragula Drag and drop so simple it hurts 480 live demo angular-drag-and-drop-lists Angular d ...
- Spark机器学习(11):协同过滤算法
协同过滤(Collaborative Filtering,CF)算法是一种常用的推荐算法,它的思想就是找出相似的用户或产品,向用户推荐相似的物品,或者把物品推荐给相似的用户.怎样评价用户对商品的偏好? ...