重構實踐——爲了try-catch大興排場

多是咱們共同的強迫症,不要說看到,就算想到太多的try-catch也很難接受。html

因而,開始了一些嘗試,這些嘗試都算是思惟的鍛鍊、場面的見識、經驗的積累。框架

Version1 —— 原始版本

一開始,在ConcreteService中,擁有了太多的try-catch,而影響碼字的興趣。函數

代碼1 原始代碼
/// <summary>
/// 契約
/// </summary>
public interface IUpdateManyManyThingContract
{
    bool UpdateSth1(DataSet ds);
    bool UpdateSth2(DataSet ds);
    bool UpdateSth3(DataSet ds);
    bool UpdateSth4(DataSet ds);
    //...
}

/// <summary>
/// 服務實現
/// </summary>
public class ConcreteService : IUpdateManyManyThingContract
{
    private IDao m_Dao;

    public bool UpdateSth1(DataSet ds)
    {
        try
        {
            var dt = ds.First();
            if (!dt.HasElements()) return true;

            foreach (DataRow row in dt.Rows)
            {
                //構造
                var entity = new Branch(row);
                m_Dao.SaveOrUpdate(entity);
            }
            return true;
        }
        catch (Exception ex)
        {
            Logger.Log(ex);
            return false;
        }
    }

    public bool UpdateSth2(DataSet ds)
    {
        try
        {
        }
        catch (Exception)
        {
        }
    }

    public bool UpdateSth3(DataSet ds)
    {
        throw new NotImplementedException();
    }

    public bool UpdateSth4(DataSet ds)
    {
        throw new NotImplementedException();
    }
    //many update methods,many try-catches...
}

如上代碼,UpdateSth函數裏面都須要實現一個try-catch,而以爲噁心到本身了。ui

Version2——(Extract Method)提取方法 + Func

因而,基於本身的積累,開始了重構的第一個版本。spa

針對這個服務(ConcreteService)的特殊性,定製了一個專門的方法進行控制——TrycatchBlock.net

代碼2 提取方法片斷
/// <summary>
/// 服務實現
/// </summary>
public class ConcreteService : IUpdateManyManyThingContract
{
    private IDao m_Dao;

    public bool UpdateSth1(DataSet ds)
    {
        return TrycatchBlock(() =>
        {
            var dt = ds.First();
            if (!dt.HasElements()) return true;

            foreach (DataRow row in dt.Rows)
            {
                //構造
                var entity = new Branch(row);
                m_Dao.SaveOrUpdate(entity);
            }
            return true;
        });
    }

    public bool UpdateSth2(DataSet ds)
    {
        return TrycatchBlock(() =>
        {
            //...
            return true;
            //...
            //return false;
        });
    }

    public bool UpdateSth3(DataSet ds)
    {
        throw new NotImplementedException();
    }

    public bool UpdateSth4(DataSet ds)
    {
        throw new NotImplementedException();
    }
    //many update methods,many try-catches...

    //try-catch控制塊
    private bool TrycatchBlock(Func<bool> body)
    {
        try
        {
            return body();
        }
        catch (Exception ex)
        {
            Logger.Log(ex);
            return false;
        }
    }
}

是的,這是一次進步,將全部的try-catch的功能職責都集中到了一個函數裏面,也方便調試了。代理

可是,還得每一個方法都加上一句:return TrycatchBlock(() => { 。。。 })。調試

從本質上來講,仍是在進行中重複。code

Version3——過濾器思想(否決)

通過老大的指點:考慮MVC中的相似FilterAttribute的註解。htm

 

思路演進:MVC中,有一個HandErrorAttribute的特性,用於攔截控制器或者動做的異常。。。。。。對,這是個思路,但過了沒多久,我就放棄了。

 

放棄理由:「Request請求——>路由數據——>ControllerInvoker——>反射調用Controller或Action。」,這裏面用了不少元數據(***Descriptor,***Invoker等)手段,實現難度不小。

 

另外,我須要的是「instance.MethodAction」(對象直接調用方法)的方式,由於是爲WCF直接提供服務(WCF會根據配置文件中服務的名稱建立服務),不須要使用反射進行動態調用。

 

Version4——動態代理

瀏覽網頁的過程當中,想起動態代理——Castle Dynamic Proxy,是的,Moq,Spring.net等一系列優秀的框架中引用到了它。

V4.1.使用中間層

想起一個老外曾經說過的一句話「計算機的任何問題,均可以經過一箇中間層來解決」,固然,這裏的中間層,是一個普遍和抽象的概念,好比,中間1調中間2中間2調目標,多是一個遞歸的結構也說不定。

 

因而使用interceptor繼續一個版本:

代碼3:中間層——ConcreteServiceProxy;攔截器——ServiceDynamicProxyInterceptor。
/// <summary>
/// 服務實現
/// </summary>
public class ConcreteService : IUpdateManyManyThingContract
{
    private IDao m_Dao;

    public bool UpdateSth1(DataSet ds)
    {
        var dt = ds.First();
        if (!dt.HasElements()) return true;

        foreach (DataRow row in dt.Rows)
        {
            //構造
            var entity = new Branch(row);
            m_Dao.SaveOrUpdate(entity);
        }
        return true;
    }

    public bool UpdateSth2(DataSet ds)
    {
        //...
        return true;
        //...
        //return false;
    }

    public bool UpdateSth3(DataSet ds)
    {
        throw new NotImplementedException();
    }

    public bool UpdateSth4(DataSet ds)
    {
        throw new NotImplementedException();
    }
    //many update methods,many try-catches...
}

public class ConcreteServiceProxy : IUpdateManyManyThingContract
{
    private ConcreteService m_Service;
    public ConcreteServiceProxy()
    {
        m_Service = ServiceDynamicProxyInterceptor.CreateServiceProxy<ConcreteService>();
    }
    public bool UpdateSth1(DataSet ds)
    {
        return m_Service.UpdateSth1(ds);
    }

    public bool UpdateSth2(DataSet ds)
    {
        return m_Service.UpdateSth2(ds);
    }

    public bool UpdateSth3(DataSet ds)
    {
        return m_Service.UpdateSth3(ds);
    }

    public bool UpdateSth4(DataSet ds)
    {
        return m_Service.UpdateSth4(ds);
    }
}

public class ServiceDynamicProxyInterceptor : IInterceptor
{
    /// <summary>
    /// 工廠方法
    /// </summary>
    /// <typeparam name="T">服務類型</typeparam>
    /// <returns>一個通過代理的服務</returns>
    public static T CreateServiceProxy<T>() where T : class
    {
        ProxyGenerator generator = new ProxyGenerator();
        ServiceDynamicProxyInterceptor interceptor = new ServiceDynamicProxyInterceptor();
        T entity = generator.CreateClassProxy<T>(interceptor);
        return entity;
    }

    public void Intercept(IInvocation invocation)
    {
        try
        {
            invocation.Proceed();
        }
        catch (Exception ex)
        {
            Log.Error(ex.Message);
            invocation.ReturnValue = false;
        }
    }
}

上述代碼是一目瞭然,使用m_Service = ServiceDynamicProxyInterceptor.CreateServiceProxy<ConcreteService>();就獲得一個代理過的對象,也就可以進行攔截

 

多了一箇中間層——ConcreteServiceProxy,井井有條了,可是代碼一樣沒有減小,這個彷佛又看起來屢次一舉。

何況還要改配置文件,WCF的配置,以下下劃線部分。

<service name="MyNameSpace.Service.ConcreteServiceProxy" behaviorConfiguration="WFServiceBehavior">

V4.2.IOC版

到使用中間層爲止,我已是可以接受的了。但老大以爲還能夠再精簡,確實是經驗豐富,又被指點了,而後提點我使用IOC,目標是去除中間層——ConcreteServiceProxy。

 

思路:

1) 先使用動態代理建立一個被代理過的(Proxied)ConcreteService對象;

2) 將此對象放入IOC中(如Autofac,Unity等);

3) 若是須要使用ConcreteService類型的實例,從IOC中獲取便可。

 

注:(去除了中間層——ConcreteServiceProxy;同時ConcreteService不用加try-catch;也不用改配置文件了)

 

代碼4:去除了中間層——ConcreteServiceProxy;同時ConcreteService不用加try-catch;也不用改配置文件了

public class DependencyRegistrar : IDependencyRegistrar
{
    public virtual void Register(ContainerBuilder builder, ITypeFinder typeFinder)
    {
        var proxiedService = ServiceDynamicProxyInterceptor.CreateServiceProxy<ConcreteService>();
        builder.Register(c => proxiedServicec).As<ConcreteService>().InstancePerRequest();
    }

    public int Order
    {
        get { return 0; }
    }
}

 

一次多好的體驗啊!!!

用DP(Dynamic Proxy)完成了攔截;用IOC完成了DI。

 

寫到這裏,問題來了,WCF可以經過配置文件配置的服務名稱,即MyNameSpace.Service.ConcreteService,自動去IOC中找到被代理的對象嗎?Autofac.WCF能不能幫助它完成呢?

 (附)動態代理連接:

http://docs.castleproject.org/Tools.DynamicProxy.ashx

http://www.cnblogs.com/daxnet/archive/2011/09/07/2169520.html

http://www.cnblogs.com/RicCC/archive/2010/03/15/castle-dynamic-proxy.html

總結:就先寫到這裏,體驗的感受哪怕就是一點點,也很爽!歡迎拍磚。

Demo連接:http://files.cnblogs.com/pengzhen/TryCatchDemo.rar

相關文章
相關標籤/搜索