分离责任,消除代码级别耦合 OO设计模式AOP编程
程序员文章站
2022-06-08 21:10:21
...
例子--安全检查.
假设希望检查用户是否有权限执行某个方法,如果没有权限就抛出一个异常,也就是说对要执行安全检查的代码进行方法拦截,以加
入检查代码.如果编程解决这个问题,OO无法给我们任何有效的帮助.得到的是这样的代码.
这个类有两个责任:主要责任是执行业务代码 Do the work of methodX.
次要责任是执行安全检查代码 doSecurityCheck.
OO可以尽可能减少重复的代码.如把安全检查代码归整到一个单独方法中去,但无法消除重复的代码,这要在每个业务方法中调用安
全检查方法.基于层级结构的OO对这种正交性的代码无法做到完全的消除重复代码.
Decorator模式:
通过Decorator模式的使用,可以将两者的责任分离,(如果安全检查代码过于复杂,可以用Extract Class将代码抽离出去).
但仍有两个问题:1.要针对每一个业务对象都要写一个装饰类。强类型在这里没有多大用处,如果一个通用类能解决问题则是最恰当
的.
2.无论怎样分离代码,最后都要在一个地方将两者进行组装, 组装的动作发生在编译期。如果能在运行时组装则能
避免代码级别的耦合.利用AOP提供的方式则能做到这一点.
Observer模式.
将安全检查代码封装到接口中去,
安全检查作为业务方法的一个次要逻辑.但Observable要通知Observer,则代码必然会发生耦合.
普通的代理模式的代码结构与上面Decorator模式基本相同.
OO设计在此问题上只能尽可能减少重复代码,尽量分离责任,但最后仍会发生代码的耦合.
AOP的总结最大成果在于提出了一套完备的切入点理论,以及让被增强的类完全对增强一无所知-- 从前的大多数拦截技术都没有做到
这一点.以实现责任在代码级别的解耦.
Dynamic Proxy
某一业务类与安全检查代码在运行时进行组装.
假设希望检查用户是否有权限执行某个方法,如果没有权限就抛出一个异常,也就是说对要执行安全检查的代码进行方法拦截,以加
入检查代码.如果编程解决这个问题,OO无法给我们任何有效的帮助.得到的是这样的代码.
public class MyBusinessObject implements BusinessObject { public void businessMethod1() throws UnauthorizedException { doSecurityCheck(); // Do the work of method1 } public void businessMethod2() throws UnauthorizedException { doSecurityCheck(); // Do the work of method2 } protected void doSecurityCheck() throws UnauthorizedException { } }
这个类有两个责任:主要责任是执行业务代码 Do the work of methodX.
次要责任是执行安全检查代码 doSecurityCheck.
OO可以尽可能减少重复的代码.如把安全检查代码归整到一个单独方法中去,但无法消除重复的代码,这要在每个业务方法中调用安
全检查方法.基于层级结构的OO对这种正交性的代码无法做到完全的消除重复代码.
Decorator模式:
//业务类 public class MyBusinessObject implements BusinessObject { public void businessMethod1() throws UnauthorizedException { // Do the work of method1 } public void businessMethod2() throws UnauthorizedException { // Do the work of method2 } } //装饰类 public abstract class BusinessObjectFilter implements BusinessObject { private BusinessObject target; public BusinessObjectFilter (BusinessObject obj) { this.target = obj; } public void businessMethod1() throws UnauthorizedException { this.target.businessMethod1(); } public void businessMethod2() throws UnauthorizedException { this.target.businessMethod2() ; } } //组合业务操作和安全检查的类 public class RealBusinessObject extends BusinessObjectFilter { public ReadBusinessObject(BusinessObject obj) { super(obj); } //1.增加安全检查代码. //2.一定要调用super.businessMethod1();否则这将不是一个增强功能的方法,而是在重写一个方法. public void businessMethod1() throws UnauthorizedException { doSecurityCheck(); super.businessMethod1(); } public void businessMethod2() throws UnauthorizedException { doSecurityCheck(); super.businessMethod2() ; } protected void doSecurityCheck() throws UnauthorizedException { } }
通过Decorator模式的使用,可以将两者的责任分离,(如果安全检查代码过于复杂,可以用Extract Class将代码抽离出去).
但仍有两个问题:1.要针对每一个业务对象都要写一个装饰类。强类型在这里没有多大用处,如果一个通用类能解决问题则是最恰当
的.
2.无论怎样分离代码,最后都要在一个地方将两者进行组装, 组装的动作发生在编译期。如果能在运行时组装则能
避免代码级别的耦合.利用AOP提供的方式则能做到这一点.
Observer模式.
将安全检查代码封装到接口中去,
//Observer public interface SecurityCheck { void doSecurityCheck() throws UnauthorizedException; } //Observable public class MyBusinessObject implements BusinessObject{ private SecurityCheck securityCheck; public void businessMethod1() throws UnauthorizedException { securityCheck.doSecurityCheck(); // Do the work of method1 } public void businessMethod2() throws UnauthorizedException { securityCheck.doSecurityCheck(); // Do the work of method2 } public void setSecurityCheck(SecurityCheck securityCheck) { this.securityCheck = securityCheck; } }
安全检查作为业务方法的一个次要逻辑.但Observable要通知Observer,则代码必然会发生耦合.
普通的代理模式的代码结构与上面Decorator模式基本相同.
OO设计在此问题上只能尽可能减少重复代码,尽量分离责任,但最后仍会发生代码的耦合.
AOP的总结最大成果在于提出了一套完备的切入点理论,以及让被增强的类完全对增强一无所知-- 从前的大多数拦截技术都没有做到
这一点.以实现责任在代码级别的解耦.
Dynamic Proxy
//业务类 public class MyBusinessObject implements BusinessObject { public void businessMethod1() throws UnauthorizedException { // Do the work of method1 } public void businessMethod2() throws UnauthorizedException { // Do the work of method2 } } //安全检查接口 public class SecurityCheckImpl implements SecurityCheck { public void doSecurityCheck() throws UnauthorizedException { //doSecurityCheck } } //组合业务类和安全检查的通用类 public class CommonSecurityCheck implements InvocationHandler { private Object target; private SecurityCheck securityCheck; private CommonSecurityCheck(Object arg0,SecurityCheck arg1) { this.target = arg0; this.securityCheck = arg1; } public Object invoke(Object proxy,Method method,Object[] args) throws Throwable { this.securityCheck.doSecurityCheck(); Object result = method.invoke(this.target,args); return result; } }
某一业务类与安全检查代码在运行时进行组装.
上一篇: 轻松学习PHP配置文件