Let's refactor it-OpenSinaAPI

这两天一直在看Clean Code以及 重构,一直想找一些例子练练手。恰巧前两天在玩新浪微博应用的时候看到了陈着写的这个SDK。down下来代码后发现这里面还有很多可以重构的地方,于是花了一个周末实践了一下。

在简单了解了下OAuth的原理及使用后,先确定了重构的范围:

1、基础类oAuthBase.cs不动,因为这个类是由官方提供的。

2、有必要时外部调用接口也需要更改(事实上写到最后几乎对所有的接口都改了)。

开始下手,先看oAuthWebRequest这个函数

 

public string oAuthWebRequest(Method method, string url, string postData)
    {
        string outUrl = "";
        string querystring = "";
        string ret = "";
        postData += "&source=" + appKey;
        if (method == Method.POST)
        {
            if (postData.Length > 0)
            {
                NameValueCollection qs = HttpUtility.ParseQueryString(postData);
                postData = "";
                foreach (string key in qs.AllKeys)
                {
                    if (postData.Length > 0)
                    {
                        postData += "&";
                    }
                    qs[key] = HttpUtility.UrlEncode(qs[key]);
                    qs[key] = this.UrlEncode(qs[key]);
                    postData += (key + "=" + qs[key]);

                }
                if (url.IndexOf("?") > 0)
                {
                    url += "&";
                }
                else
                {
                    url += "?";
                }
                url += postData;
            }
        }

        Uri uri = new Uri(url);

        string nonce = this.GenerateNonce();
        string timeStamp = this.GenerateTimeStamp();

        //Generate Signature
        string sig = this.GenerateSignature(uri,
            this.appKey,
            this.appSecret,
            this.token,
            this.tokenSecret,
            method.ToString(),
            timeStamp,
            nonce,
            out outUrl,
            out querystring);


        querystring += "&oauth_signature=" + HttpUtility.UrlEncode(sig);

        if (method == Method.POST)
        {
            postData = querystring;
            querystring = "";
        }

        if (querystring.Length > 0)
        {
            outUrl += "?";
        }

        if (method == Method.POST || method == Method.GET)
            ret = _WebRequest(method, outUrl + querystring, postData);
        return ret;
    }

这个函数的目的是来创建请求,并且将请求结果返回。

让我们来识别一下这个函数都有哪些bad smell:

1、long method.这个方法足足有70行。

2、Temporary Field.光函数开头声明的临时变量就有3个,函数内部声明的临时变量更是不尽其数。

3、Single Responsibility Principle.函数中充斥着大量的if-else,以及多处判断POST与Get。

4、Higher Cyclomatic Complexity.函数中存在可以避免的嵌套 if-else

重构的方法:

首先根据不同的请求类型(POST/GET)来声明不同的处理方法,为了使客户类调用行为一致,我这里抽取出了一个IHttpRequestMethod接口

 

public interface IHttpRequestMethod
    {
        string Request(string uri, string postData);        
    }

其中Request方法相当于原库中oAuthWebRequest,分别用两个类HttpGet与HttpPost来实现。

然后是将这个方法拆解成为几个小方法。最后的代码如下:

 

 public class HttpPost : BaseHttpRequest
    {
        .....
        ......

        public override string Request(string uri, string postData)
        {
            var appendUrl = AppendPostDataToUrl(postData, uri);
            string outUrl;
            var querystring= AppendSignatureString(POST, appendUrl, out outUrl);
            return WebRequest(POST, outUrl, querystring);
        }
        ......
    }

 

 

 public class HttpGet : BaseHttpRequest
    {
       .......
        ......

        public override string Request(string uri, string postData)
        {
            string outUrl;
            var queryString = AppendSignatureString(GET, uri, out outUrl);
            if (queryString.Length > 0)
            {
                outUrl += "?";
            }
            return WebRequest(GET, outUrl + queryString);
        }
       ......
     }

全部代码参见:

http://code.google.com/p/opensinaapi/downloads/detail?name=OpenSinaApi04-18-2011.rar

欢迎各位看官一起动手来进一步重构:)

Posted by Leo 2011年4月17日 18:47