20181122_C#中AOP初探_装饰器模式的AOP_Remoting实现AOP_Castle实现AOP
一. 什么是AOP:
a) AOP是面向切面编程; 就像oop一样, 它也是一种编程思想;
i. Oop思想→一切皆对象, 对象交互组成功能, 功能叠加组成模块, 模块叠加组成系统; 如果把一个个的类比喻成一个个砖头, 那么系统就是一个房子; 房子是由一块块砖头构成, 所以面向对象非常适合做大型系统; 但是面向对象的在应对系统扩展的时候, 就显得力不从心; 如果砖块需要发生变化, 则就会牵扯到很多地方; 因为面向对象是静态的, 内部就是强耦合的关系; 虽然设计模式可以解决这些问题中的某些部分, 比如可以创建出可扩展, 可重用的架构, 但是设计模式操作的最小单元也是类(砖头), 无法解决类的内部的变化
ii. AOP→面向切面编程, 是对OOP的补充; 主要功能就是为了解决类的内部变化, 在不破坏类封装的同时, 水平扩展类的功能; 降低模块间的耦合度; 注意AOP不是实现业务行为的: 比如一个People类, 本身具有跑步, 吃饭, 睡觉这三个方法, 但是如果你想通过AOP为其增加一个 游泳 的方法, 那么AOP就不适用了; 因为这种属于业务层面, 在封装类的时候, 就应该存在的行为; AOP主要是用来做一些通用的功能, 比如 权限校验/日志记录/发送消息/缓存处理/性能监控 等等一些通用的非业务逻辑的功能;
iii. 总结:
- 所以说AOP 只是对OOP思想的一种补充, 解决类的内部通用功能的变化
- 所有的业务功能还是由OOP来实现, 比如People类需要增加 游泳 方法, 还是得有OOP来完成
- 有了AOP之后, OOP的实现也变得简单了, 因为OOP的代码, 只用关注业务逻辑; 无需再操心各种通用的功能了
二. 利用装饰器模式实现简答的AOP, 没有通用性:
a) 实现代码:
/// <summary>
/// 1. 这个接口定义一个注册用户的行为
/// </summary>
public interface IUserProcessor
{
void RegUser(User user);
} /// <summary>
/// 2. 普通的实现
/// </summary>
public class UserProcessor : IUserProcessor
{
public void RegUser(User user)
{
Console.WriteLine("用户已注册。Name:{0},PassWord:{1}", user.Name, user.Password);
}
} /// <summary>
/// 3. 利用装饰器模式的实现, 这个就类似于简单的AOP功能,
/// 装饰器即实现了IuserProcessor的接口
/// 但在实现的同时, 还组合进一个IuserProcessor对象;
/// 这就是一个标准的装饰器模式
/// </summary>
public class UserProcessorDecorator : IUserProcessor
{
//组合一个IUserProcessor对象
private IUserProcessor _UserProcessor { get; set; }
public UserProcessorDecorator(IUserProcessor userprocessor)
{
this._UserProcessor = userprocessor;
}
//实现接口
public void RegUser(User user)
{
BeforeProceed(user); this._UserProcessor.RegUser(user); AfterProceed(user);
} /// <summary>
/// 定义在业务逻辑执行之前要执行的动作
/// </summary>
/// <param name="user"></param>
private void BeforeProceed(User user)
{
Console.WriteLine("方法执行前");
}
/// <summary>
/// 定义在业务逻辑执行之后要执行的动作
/// </summary>
/// <param name="user"></param>
private void AfterProceed(User user)
{
Console.WriteLine("方法执行后");
}
}
b) 调用
public static void Show()
{
User user = new User()
{
Name = "孙悟空",
Password = "123456"
}; //5. 装饰器模式使用的方法
IUserProcessor processor = new UserProcessor();
processor.RegUser(user); //普通实现 Console.WriteLine("***************"); user = new User()
{
Name = "八戒AOP",
Password = "567890"
};
processor = new UserProcessorDecorator(processor);
processor.RegUser(user);//使用装饰器模式实现的AOP, 看起来只为此类的此方法单独实现的, 有很大局限性
}
c) 执行结果截图:
三. 使用.net Remoting实现动态代理(AOP), 不太推荐, .net Remoting对父类的限制实在是太大了
a) 创建一个接口, 这里和装饰器模式没有什么区别
/// <summary>
/// 1. 使用.net Remoting 来实现动态代理, 这里的业务还是和装饰器与代理模式的业务一样
/// </summary>
public interface IUserProcessor
{
void RegUser(User user);
}
b) 实现接口, 并继承MarshalByRefObject
/// <summary>
/// 必须继承自MarshalByRefObject父类,否则无法生成;
/// 这个继承就感觉比较恶心了;因为C#中都是单继承的
///
/// 2. 定义一个UserProcessor来实现IUserProcessor, 必须继承一个MarshalByRefObject; 继承此类是.net Remoting的固定写法类; 如果想实现动态代理就必须继承这个类(MarshalByRefObject)
/// </summary>
public class UserProcessor : MarshalByRefObject, IUserProcessor
{
public void RegUser(User user)
{
Console.WriteLine("用户已注册。用户名称{0} Password{1}", user.Name, user.Password);
}
}
c) 使用Remoting进行对象生成的动态代理的固定写法
/// <summary>
/// MyRealProxy<T> 就是真实代理, 这个类里面的东西, 属于固定写法, 是.net Remoting封装好的
/// </summary>
/// <typeparam name="T"></typeparam>
public class MyRealProxy<T> : RealProxy
{
private T tTarget;
public MyRealProxy(T target): base(typeof(T))
{
this.tTarget = target;
} /// <summary>
/// .net Remoting的核心方法
/// </summary>
/// <param name="msg"></param>
/// <returns></returns>
public override IMessage Invoke(IMessage msg)
{
BeforeProceede(msg); //在执行方法之前做一些其它自定义的动作 //这里执行真实的方法体, 在这个方法体之前(之后)都可以加一点自己的动作
IMethodCallMessage callMessage = (IMethodCallMessage)msg;
object returnValue = callMessage.MethodBase.Invoke(this.tTarget, callMessage.Args); AfterProceede(msg);//在执行方法之后执行一些其它动作 return new ReturnMessage(returnValue, new object[0], 0, null, callMessage);
}
#region 可以扩展的逻辑
public void BeforeProceede(IMessage msg)
{
Console.WriteLine("方法执行前可以加入的逻辑");
}
public void AfterProceede(IMessage msg)
{
Console.WriteLine("方法执行后可以加入的逻辑");
}
#endregion
}
/// <summary>
/// 透明代理; 固定的写法, 表示如何使用.net Remoting来生成对象
/// </summary>
public static class TransparentProxy
{
public static T Create<T>()
{
//使用反射动态创建对象
T instance = Activator.CreateInstance<T>();
//将对象包装一层, 交给MyRealProxy
MyRealProxy<T> realProxy = new MyRealProxy<T>(instance);
//GetTransparentProxy→父类的方法
T transparentProxy = (T)realProxy.GetTransparentProxy();
return transparentProxy;
}
}
d) 调用方法:
public static void Show()
{
User user = new User()
{
Name = "孙悟空",
Password = "123456"
}; UserProcessor processor = new UserProcessor();
processor.RegUser(user);
Console.WriteLine("*********************"); user = new User()
{
Name = "八戒AOP",
Password = "567890"
};
//利用TransparentProxy来创建对象
UserProcessor userProcessor = TransparentProxy.Create<UserProcessor>();
//调用RegUser时, 会进入到Invoke方法中, 至于为什么会进入到Invoke中, 是由.net Remoting的底层来实现的
userProcessor.RegUser(user);
}
e) 执行结果:
四. 使用Castle实现动态代理
对于Castle来说, 实现接口时, 方法必须是一个虚方法; 主要代码如下:
/// <summary>
/// 使用Castle\DynamicProxy 实现动态代理
/// 方法必须是虚方法
/// </summary>
public class CastleProxyAOP
{
/// <summary>
/// 1. 业务和动态代理/装饰器模式/.net Remoting(RealProxy)都是一样, 定义接口对象
/// </summary>
public interface IUserProcessor
{
void RegUser(User user);
} /// <summary>
/// 2. 业务子类实现IUserProcessor接口
/// </summary>
public class UserProcessor : IUserProcessor
{
/// <summary>
/// 必须带上virtual 否则无效
/// </summary>
/// <param name="user"></param>
public virtual void RegUser(User user)
{
Console.WriteLine($"用户已注册。Name:{user.Name},PassWord:{user.Password}");
}
} /// <summary>
/// 3. 这里是个重点, Intercept()方法是个重点
/// </summary>
public class MyInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
//在方法调用之前执行的动作
PreProceed(invocation);
invocation.Proceed(); //这里是真实的方法调用
//在方法调用之后执行的动作
PostProceed(invocation);
}
public void PreProceed(IInvocation invocation)
{
Console.WriteLine("方法执行前");
} public void PostProceed(IInvocation invocation)
{
Console.WriteLine("方法执行后");
}
} public static void Show()
{
User user = new User()
{
Name = "孙悟空",
Password = "456789"
}; //4. 调用
ProxyGenerator generator = new ProxyGenerator();
MyInterceptor interceptor = new MyInterceptor(); //5. 创建对象; (这个也是动态实现的AOP); 固定写法
// 基于里式替换原则,右边是父类, 那么在调用的时候, 根本就不会去管左边是个什么, 直接会调用父类的RegUser方法, 如果要调用子类的RegUser方法, 则必须标注virtual
UserProcessor userprocessor = generator.CreateClassProxy<UserProcessor>(interceptor);
userprocessor.RegUser(user);
} }
20181122_C#中AOP初探_装饰器模式的AOP_Remoting实现AOP_Castle实现AOP的更多相关文章
- 聊聊模板方法模式,装饰器模式以及AOP
在软件系统设计的时候,我们需要把一个大的系统按照业务功能进行拆分,做到高内聚.低耦合. 但是呢,拆分之后会产生一些通用性的东西,比如日志,安全,事务,性能统计等,这些非功能性需求,横跨多个模块.最lo ...
- 2.静态AOP实现-装饰器模式
通过装饰器模式实现在RegUser()方法本身业务前后加上一些自己的功能,如:BeforeProceed和AfterProceed,即不修改UserProcessor类又能增加新功能 定义1个用户接口 ...
- java设计模式之装饰器模式以及在java中作用
在JAVA I/O类库里有很多不同的功能组合情况,这些不同的功能组合都是使用装饰器模式实现的,下面以FilterInputStream为例介绍装饰器模式的使用 FilterInputStream和F ...
- JS 设计模式九 -- 装饰器模式
概念 装饰者(decorator)模式能够在不改变对象自身的基础上,动态的给某个对象添加额外的职责,不会影响原有接口的功能. 模拟传统面向对象语言的装饰者模式 //原始的飞机类 var Plane = ...
- 装饰器模式(Decorator)
一.装饰模式介绍 装饰模式(decorator):表示动态的给一个对象添加一些新的功能(利用子类继承父类也可以实现),但是比生成子类方式更灵活. 也叫装饰者模式或者装饰器模式 例如:我们每个人身上穿的 ...
- Python设计模式-装饰器模式
装饰器模式 装饰器模式,动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式比生成子类更为灵活. 代码示例 #coding:utf-8 #装饰器模式 class Beverage(): ...
- 重学 Java 设计模式:实战装饰器模式(SSO单点登录功能扩展,增加拦截用户访问方法范围场景)
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 对于代码你有编程感觉吗 很多人写代码往往是没有编程感觉的,也就是除了可以把功能按照固 ...
- PHP 装饰器模式
装饰器模式:是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能. [装饰器模式中主要角色] 抽象组件角色(Component):定义一个对象接口,以规范准备接受附加责任的对象,即可以给这 ...
- 设计模式-装饰器模式(Decrator Model)
文 / vincentzh 原文连接:http://www.cnblogs.com/vincentzh/p/6057666.html 目录 1.概述 2.目的 3.结构组成 4.实现 5.总结 1.概 ...
随机推荐
- Java并发编程之读写锁
读写锁维护了一对相关的锁,一个用于只读操作,一个用于写入操作.只要没有writer,读取锁可以由多个reader线程同时保持.写入锁是独占的. 可重入读写锁 ReentrantReadWriteLoc ...
- HAWQ中的行列转置
行列转置是ETL或报表系统中的常见需求,HAWQ提供的内建函数和过程语言编程功能,使行列转置操作的实现变得更为简单. 一.行转列 1. 固定列数的行转列 原始数据如下: test=# select * ...
- Python如何输出带颜色的文字
print('\033[31m%s' % "这是前景色") 这是前景色 print('%s' % "这是前景色") 这是前景色 print('\033[1;31 ...
- oracle管道函数的用法
oracle管道函数是一类特殊的函数,oracle管道函数返回值类型必须为集合,下面将介绍oracle管道函数的语法. 在普通的函数中,使用dbms_output输出的信息,需要在服务器执行完整个函数 ...
- wireshark的提示
内容:12个wrieshark的提示 1.[Packet size limited during capture] 在捕获数据包大小有限,即包没有抓全 2.[TCP previous segment ...
- 使用vue
使用bootstrap npm install bootstrap@3 --save 使用jQuery npm install jQuery --save ---------------- 搭建vue ...
- day4(带)
int is_his_file(char*filename,char *username) { int ret; struct passwd *user_info;// struct stat sta ...
- RUAL1519 Formula 1 【插头DP】
RUAL1519 Formula 1 Background Regardless of the fact, that Vologda could not get rights to hold the ...
- HDU2896 病毒侵袭 【AC自动机】
HDU2896 病毒侵袭 Problem Description 当太阳的光辉逐渐被月亮遮蔽,世界失去了光明,大地迎来最黑暗的时刻....在这样的时刻,人们却异常兴奋--我们能在有生之年看到500年一 ...
- 如何通过eclipse查看、阅读hadoop2.4源码
问题导读:1.官网src包下载包,能否直接使用?2.如何跟踪和查看hadoop源码? 此篇是从零教你如何获取hadoop2.4源码并使用eclipse关联hadoop2.4源码基础上的一个继续,上文其 ...