Heim  >  Artikel  >  Backend-Entwicklung  >  Erinnern Sie sich an ein .NET-Code-Refactoring (Teil 2)

Erinnern Sie sich an ein .NET-Code-Refactoring (Teil 2)

黄舟
黄舟Original
2017-02-06 14:40:291159Durchsuche

public override bool TryGetMember(GetMemberBinder binder, out object result)
{
            if (!_dictionary.TryGetValue(binder.Name, out result))
            {
                result = null;
                return true;
            }
            var dictionary = result as IDictionary<string, object>;
            if (dictionary != null)
            {
                result = new DynamicJsonObject(dictionary);
                return true;
            }
            var arrayList = result as ArrayList;
            if (arrayList != null && arrayList.Count > 0)
            {
                if (arrayList[0] is IDictionary<string, object>)
result = new List<object>(arrayList.Cast<IDictionary<string, object>>().Select(x => new DynamicJsonObject(x)));
                else
                    result = new List<object>(arrayList.Cast<object>());
            }
            return true;
        }
    }
    #endregion
}

Als nächstes folgt die GetContent-Methode. Der Zweck dieser Methode besteht darin, den endgültigen SMS-Inhalt basierend auf den vom Kunden übergebenen Vorlagenvariablenparametern zusammenzustellen. Diese Methode enthielt eine harte Codierung, jetzt müssen wir sie auf dynamische Erfassung umstellen.

Beispiel für den Inhalt einer Textnachrichtenvorlage:

【一应生活】您有一件单号为expressNumbers company,已到communityName收发室,请打开一应生活APP“收发室”获取取件码进行取件。
点击下载http://a.app.qq.com/o/simple.jsp?pkgname=com.ening.life

Ich habe festgestellt, dass es ein Problem mit dem Inhalt einer solchen Vorlage gibt. Die variablen Parameter in der Vorlage werden direkt in englischen Wörtern ausgedrückt. Und in unserem Textnachrichteninhalt können manchmal englische Wörter vorkommen, daher füge ich allen variablen Parametern {} hinzu. Die Änderung ist wie folgt:

【一应生活】您有一件单号为{expressNumbers} {company},已到{communityName}收发室,
请打开一应生活APP“收发室”获取取件码进行取件。点击下载http://a.app.qq.com/o/simple.jsp?pkgname=com.ening.life

Wir müssen die variablen Parameter in der SMS-Vorlage durch die Werte ersetzen, die den variablen Parametern entsprechen, basierend auf dem vom Kunden übergebenen Objekt. Dann müssen wir zuerst die Schlüssel-Wert-Paar-Informationen in diesem Objekt analysieren.

  /// 把object对象的属性反射获取到字典列表中
        /// </summary>
        /// <param name="data">object对象</param>
        /// <returns>返回Dictionary(属性名,属性值)列表</returns>
         static Dictionary<string, string> GetProperties(object data)
        {
            Dictionary<string, string> dict = new Dictionary<string, string>();

            Type type = data.GetType();
            string[] propertyNames = type.GetProperties().Select(p => p.Name).ToArray();
            foreach (var prop in propertyNames)
            {
                object propValue = type.GetProperty(prop).GetValue(data, null);
                string value = (propValue != null) ? propValue.ToString() : "";
                if (!dict.ContainsKey(prop))
                {
                    dict.Add(prop, value);
                }
            }
            return dict;
        }

Der nächste Schritt besteht darin, den Inhalt der Textnachrichtenvorlage mithilfe regulärer Ausdrücke abzugleichen.

  /// 多个匹配内容
        /// </summary>
        /// <param name="sInput">输入内容</param>
        /// <param name="sRegex">表达式字符串</param>
        /// <param name="sGroupName">分组名, ""代表不分组</param>
        static List<string> GetList(string sInput, string sRegex, string sGroupName)
        {
            List<string> list = new List<string>();
            Regex re = new Regex(sRegex, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
            MatchCollection mcs = re.Matches(sInput);
            foreach (Match mc in mcs)
            {
                if (sGroupName != "")
                {
                    list.Add(mc.Groups[sGroupName].Value);
                }
                else
                {
                    list.Add(mc.Value);
                }
            }
            return list;
        }
        public static string ReplaceTemplate(string template, object data)
        {
            var regex = @"\{(?<name>.*?)\}";
            List<string> itemList = GetList(template, regex, "name"); //获取模板变量对象
            Dictionary<string, string> dict = GetProperties(data);
            foreach (string item in itemList)
            {
                //如果属性存在,则替换模板,并修改模板值
                if (dict.ContainsKey(item))
                {
                    template = template.Replace("{"+item+"}", dict.First(x => x.Key == item).Value);
                }
            }
            return template;
}

Auf diese Weise wird das vom Kunden übergebene Objekt von unserem Parsing-Code entkoppelt. Das vom Kunden übergebene Objekt hängt nicht mehr von unserer Code-Implementierung ab, sondern vom Vorlageninhalt in unserer Datentabelle . Konfiguration.

Ich habe diese Methoden geschrieben und werde einen Unit-Test durchführen, um zu überprüfen, ob er den gewünschten Effekt hat. Leider gibt es in diesem Projekt überhaupt keine Möglichkeit, einen zu erstellen Unit-Test selbst

[TestClass]
    public class MatchHelperTest
    {
        [TestMethod]
        public void ReplaceTemplate()
        {
            //模板文本
            var template = "【一应生活】您有一件单号为{expressNumbers} {company},已到{communityName}收发室,
            请打开一应生活APP“收发室”获取取件码进行取件。点击下载http://a.app.qq.com/o/simple.jsp?pkgname=com.ening.life";
            //数据对象
            var data = new { expressNumbers = "2016", company = "长城", communityName = "长怡花园"};
            string str = "【一应生活】您有一件单号为2016 长城,已到长怡花园收发室,
            请打开一应生活APP“收发室”获取取件码进行取件。点击下载http://a.app.qq.com/o/simple.jsp?pkgname=com.ening.life";
            string str1=MatchHelper.ReplaceTemplate(template, data);

            Assert.AreEqual(str1,str);

            //重复标签的测试
            template = "【一应生活】您有一件单号为{expressNumbers} {company},已到{communityName}收发室,单号:{expressNumbers}";
            str = "【一应生活】您有一件单号为2016 长城,已到长怡花园收发室,单号:2016";
            str1=MatchHelper.ReplaceTemplate(template, data);
            Assert.AreEqual(str1, str);
        }
    }

Apropos Unit-Test: Ich glaube, dass er in vielen Unternehmen aus zu vielen Gründen nicht verwendet wird. Ich denke auch, dass es keine Notwendigkeit gibt, Unit-Tests zu schreiben. Wenn Sie sagen, dass das Schreiben von Unit-Tests keine Zeit in Anspruch nimmt, ist das definitiv eine Lüge Das Schreiben von Unit-Tests kann die Effizienz des Projekts verbessern und die Nacharbeitsrate reduzieren, denn selbst wenn Sie keine Unit-Tests schreiben, können Sie dies durch viele andere ausgleichen Persönliche Meinung, nicht kritisieren.

Als nächstes ändern Sie die GetContent-Methode wie folgt:

public string GetContent(dynamic messageContext)
{
            string strMsg = "";
            string TypeCode = string.IsNullOrEmpty(messageContext.serviceCode) ? "001" : messageContext.serviceCode;
            string channel = messageContext.channel;
            try{
var Module = unitOfWork.MessageModule.Get(c => c.Type == channel && c.TypeNo == TypeCode).FirstOrDefault();
                if (!string.IsNullOrEmpty(Module.Content))
                {
                    var content = Module.Content;
                    strMsg = MatchHelper.ReplaceTemplate(content, messageContext);
                }
                return strMsg;
            }
            catch (Exception ex)
            {
                strMsg = ex.Message;
            }
            return strMsg;
        }

(Außerdem: Beschweren wir uns über die vorherigen Variablennamen, MessageContext messageContext und String messageContent, sie sehen zu ähnlich aus. Ich habe sie wiederholt Erstens habe ich beim Erstellen einen Fehler gemacht. Es wird empfohlen, keine ähnlichen Variablennamen in derselben Methode zu verwenden. Verdammt, ich wurde wieder betrogen, also habe ich es entschieden umbenannt


Es stellt sich heraus, dass der Controller den Geschäftslogikcode direkt auf diese Weise aufruft

MessageModuleBusiness message
ModuleBusiness = new MessageModuleBusiness()
Es hängt von der Implementierung der jeweiligen Klasse ab, und wir wissen, dass die Spezifisch ist instabil, Abstraktion ist stabil, wir sollten für Schnittstellen programmieren. Heute verschicken Sie Textnachrichten, morgen vielleicht E-Mails oder fügen Protokolleinträge hinzu usw.

public interface IMessageModuleBusiness
{
        /// <summary>
        /// 组装消息内容
        /// </summary>
        /// <param name="messageContext">动态参数对象</param>
        /// <returns>组装后的消息内容</returns>
        string GetContent(dynamic messageContext);
}
Dann wird der Aufrufcode geändert in:

private IMessageModuleBusiness message
ModuleBusiness = new MessageModuleBusiness();
Der endgültige externalMerchantSendMessage-Code lautet:

    /// 外部商户发送信息
        public ActionResult externalMerchantSendMessage()
        {
            try
            {
                dynamic param = null;
                string json = Request.QueryString.ToString();

                if (Request.QueryString.Count != 0) //ajax get请求
                {
                    //兼容旧的客户调用写法,暂时硬编了
                    if (json.Contains("param."))
                    {
                        json = json.Replace("param.", "");
                    }
                    json = "{" + json.Replace("=", ":&#39;").Replace("&", "&#39;,") + "&#39;}";
                }
                else  //ajax Post请求
                {
Request.InputStream.Position = 0;//切记这里必须设置流的起始位置为0,否则无法读取到数据
                    json = new StreamReader(Request.InputStream).ReadToEnd();
                }
                var serializer = new JavaScriptSerializer();
                serializer.RegisterConverters(new[] { new DynamicJsonConverter() });
                param = serializer.Deserialize(json, typeof(object));
                logger.Info("[externalMerchantSendMessage]param:" + param);
                bool isAuth = authModelBusiness.isAuth(param.channel, param.phone, param.sign);
                if (!isAuth)
                {
                    return Json(new Result<string>()
                    {
                        resultCode = ((int)ResultCode.NoPermission).ToString(),
                        resultMsg = "签名或无权限访问"
                    }, JsonRequestBehavior.AllowGet);
                }

                var meaage = messageModuleBusiness.GetContent(param);

                if (string.IsNullOrEmpty(meaage))
                {
                    return Json(new Result<string>()
                    {
                        resultCode = ((int)ResultCode.failure).ToString(),
                        resultMsg = "发送失败"
                    }, JsonRequestBehavior.AllowGet);
                }
                SMSHelper helper = new SMSHelper();
                helper.SendSMS(meaage, param.phone); //发送短信
                return Json(new Result<string>()
                {
                    resultCode = ((int)ResultCode.success).ToString(),
                    resultMsg = "发送成功"
                }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception ex)
            {
                return Json(new Result<string>()
                {
                    resultCode = ((int)ResultCode.failure).ToString(),
                    resultMsg = "发送失败"+ex.Message
                }, JsonRequestBehavior.AllowGet);
            }
        }
In diesem Fall, auch wenn er gesendet wird durch Reflexion oder IOC in der Zukunft Es ist auch praktisch, wieder zu entkoppeln.


Okay, durch diese schrittweise Rekonstruktion habe ich die Änderungen gekapselt, ohne die ursprüngliche Tabellenstruktur zu ändern und ohne Auswirkungen auf Kundenaufrufe, wenn die Vorlagenparametervariablen des Kunden Wenn Sie eine Änderung vornehmen, muss der Code nicht geändert werden. Es muss lediglich der Vorlageninhalt in der Tabelle geändert werden.

Erinnern Sie sich an ein .NET-Code-Refactoring (Teil 2)

Beim Refactoring ist es eine sehr gute Angewohnheit, Klassendiagramme zu zeichnen. Die Codestruktur ist auf einen Blick klar.

Das Obige ist der Inhalt einer .NET-Code-Rekonstruktion (Teil 2). Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (www.php.cn)!


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn