不是架构的架构之五:业务层的实现与自动代理(补充)

在上一篇中,我们提到了通过spring.net的自动代理生成自动适应配置的业务层,也简单提到了自动代理实现的原理,但是,由于自动代理是一个比较复杂的机制,尤其对于没有架构设计经验的朋友来说,所以在今天的文章中,主要是分析spring.net的自动代理的原理,然后对我们实现的业务层做一些分析和总结。

 


我们再来回顾一下调用自动代理的代码:

 

public static T Get<T>(T instance) where T : class
{
    var p = new ProxyFactory(instance);
    p.AddAdvice(new AroundAdvise());
    return p.GetProxy() as T;
}

在方法中接收了一个泛型参数:业务对象的实例,这个业务对象当然必须是class,返回一个经过spring.net框架包装后的自动代理对象,这个自动代理对象类型仍然是T,显然这个对象和传入的对象看起来是一致的。

首先创建了一个代理工厂,我们预先将需要注入到业务对象的代码写到AroundAdvise类中,这里将AroundAdvise类添加到代理工厂,通过代理工厂获取到的业务对象,实际上是返回了一个继承了业务对象的代理对象。见下图。

image

在图中,我们传入的业务对象是UserBiz,而返回的是经过自动代理后生成的随机名称的对象。

在spring.net内部实际上是通过Emit生成的IL代码。事实上,通过CodeDom也可以实现相类似的功能,几年前我曾经实现过一个基于CodeDom的数据持久框架,性能比目前大多数ORM性能都要好得多,但是由于工作原因,没有将其做完善就放下了。在.net 3.5框架中,我们还可以使用lambda表达式来实现类似的功能,通过lambda表达式性能和Emit相近,但是复杂性远低于Emit。而在.net4.0框架中,还可以使用动态语言ironpython来实现。

 


我们来看看一段业务层的代码。

 

public class UserBiz
{
    public static UserBiz Instance { get; private set; }
    static UserBiz()
    {
        Instance=BizAutoWcfProxy.Get(new UserBiz());
    }
    private UserBiz() { }

    public virtual User GetFirst(string user,string pwd)
    {
        using (var db = Db.Get())
        {
            return User.Schema.QueryFirst(db, User.Schema.Name == user & User.Schema.Pwd == pwd);
        }
    }
}

这是一个用户业务类的代码,业务对象不需要继承任何对象,也不需要实现任何接口,但是我们在编写业务对象的时候,仍然要遵循一些约定:

1.隐藏构造函数。使用private定义的无参构造函数,避免在不熟悉的程序员直接去new这个业务对象。表现层调用业务层一律通过业务对象.Instance来得到。

2.业务层方法需要都是virtual定义。由于自动代理的缘故,在自动代理对象中需要自动重新实现所有的业务方法,所以业务方法需要是可覆盖的。

3.方法传入传出参数必须是可序列化的。

4.在业务层中不允许方法重载。这个是由于我们的设计所限,我们昨天提到,通过wcf调用的时候,传给服务端的仅仅是方法名称,如果重载了方法,可能会导致调用错误。

使用这个业务方法:

var user = UserBiz.Instance.GetFirst(username, encodePwd);


使用完全透明,在开发表现层时,完全不需要考虑应用环境的问题。

posted @ 2011-01-25 11:30  一味  阅读(814)  评论(0编辑  收藏  举报