用RealProxy实现AOP

MSDN上看到篇关于用RalProxy实现AOP的文章,于是对RealProxy做了下研究

RealProxy是什么

RealProxy是Remote技术的一部分,是跨类型远程对象的透明代理,Remote技术已经逐渐被WCF代替,我也没深入研究过,因为我的工作中用不到。

实现AOP

Box有两个方法,要在这两个日期调用前和调用后加上日志,简单粗暴的方法是在代码是直接加,但如果有很多个类似的class要加,BigBox,SmallBox,SuperBox……

    public class Box
    {
        void Open() { }
        void Close() { }
    }

按OOP的思想将Box抽象化,做为基类,然后使用Decorator模式来实现日志功能

    public abstract class Box
    {
        public abstract void Open();
        public abstract void Close();
    }

    public class BixBox : Box
    {
        public void Open()
        {
        }

        public void Close
        { 
        }
    }

    public class BoxDecorator
    {
        private Box box = null;
        public BoxDecorator(Box box)
        {
            this.box = box;
        }

        public void Open()
        {
            Console.WriteLine("Log before box open");
            box.Open();
            Console.WriteLine("Log after box open");
        }

        public void Close()
        {
            Console.WriteLine("Log before box open");
            box.Close();
            Console.WriteLine("Log after box open");
        }
    }

 

Decorator可以完成所有从Box基类派出来出的类型日志功能,但是如果不是派生自Box类呢,系统中有茫茫多的类,都要创建一个Decorator! 这还是一项庞大的代码活。

使用RealProxy实现日志功能

RealProxy的构造函数

protected RealProxy(
	Type classToProxy
)

classToProxy代理的对象必需是一个抽象类(MSDN上关于RealProxy的说明:The RealProxy class is the abstract base class from which proxies must derive.)而我在代码调试中发现它必需是个interface类型才行,否刚会出现isMarshalByRef异常,的马Box抽象类要改成一个interface

public interface Box
{
    void Open();
    void Close();
}

创建AProxy代理类

public class AProxy : RealProxy
{
    private readonly object _decorated;

    public AProxy(Box decorated)
        : base(typeof(Box))
    {
        _decorated = decorated;
    }
    private void Log(string msg, object arg = null)
    {
        Console.ForegroundColor = ConsoleColor.Red;
        Console.WriteLine(msg, arg);
        Console.ResetColor();
    }
    public override IMessage Invoke(IMessage msg)
    {
        var methodCall = msg as IMethodCallMessage;
        var methodInfo = methodCall.MethodBase as MethodInfo;
        Log("Proxy - Before executing '{0}'",
          methodCall.MethodName);
        try
        {
            var result = methodInfo.Invoke(_decorated, methodCall.InArgs);
            Log("Proxy - After executing '{0}' ",
              methodCall.MethodName);
            return new ReturnMessage(result, null, 0,
              methodCall.LogicalCallContext, methodCall);
        }
        catch (Exception e)
        {
            Log(string.Format(
              "Proxy- Exception {0} executing '{1}'", e),
              methodCall.MethodName);
            return new ReturnMessage(e, methodCall);
        }
    }
}

AProxy必需重写RealProxy的抽象方法Invoke,可以看到invoke方法内部使用反射取到方法的名称和参数值,如果不使用RealProxy,也可以完全通过.net的反射机制来完成这个功能,RealProxy已经为我们了一个轻量框架。

使用AProxy

static void Main(string[] args)
{
    Box bigBox = new BigBox() as Box;
    AProxy proxyCustomer = new AProxy(bigBox);
    Box myEntity = proxyCustomer.GetTransparentProxy() as Box;
    myEntity.Open();
    myEntity.Close();
}

运行结果:

image

完整代码

 

AProxy要求一个Box类型的参数,还没有解决先前所提到的问题,AProxy依赖Box,那么将要将解偶

image

使用泛型类解偶

修改AProxy为泛型类

    public class AProxy<T> : RealProxy
    {
        private readonly T _decorated;

        public AProxy(T decorated)
            : base(typeof(Box))
        {
            _decorated = decorated;
        }
        private void Log(string msg, object arg = null)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(msg, arg);
            Console.ResetColor();
        }
        public override IMessage Invoke(IMessage msg)
        {
            var methodCall = msg as IMethodCallMessage;
            var methodInfo = methodCall.MethodBase as MethodInfo;
            Log("Proxy - Before executing '{0}'",
              methodCall.MethodName);
            try
            {
                var result = methodInfo.Invoke(_decorated, methodCall.InArgs);
                Log("Proxy - After executing '{0}' ",
                  methodCall.MethodName);
                return new ReturnMessage(result, null, 0,
                  methodCall.LogicalCallContext, methodCall);
            }
            catch (Exception e)
            {
                Log(string.Format(
                  "Proxy- Exception {0} executing '{1}'", e),
                  methodCall.MethodName);
                return new ReturnMessage(e, methodCall);
            }
        }
    }

客户端使用方法修改

        static void Main(string[] args)
        {
            Box bigBox = new BigBox() as Box;
            AProxy<Box> proxyCustomer = new AProxy<Box>(bigBox);
            Box myEntity = proxyCustomer.GetTransparentProxy() as Box;
            myEntity.Open();
            myEntity.Close();
        }


如此一来AProxy就可以代理所有类型,达到目的

image

posted @ 2014-03-07 23:12  徐某人  阅读(1570)  评论(0编辑  收藏  举报