Souvenez-vous d'une refactorisation de code .NET (Partie 2)

黄舟
Libérer: 2017-02-06 14:40:29
original
1208 Les gens l'ont consulté

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
}
Copier après la connexion

Vient ensuite la méthode GetContent. Le but de cette méthode est très simple. Il s'agit d'assembler le contenu SMS final en fonction des paires clé-valeur de paramètre de variable de modèle et du contenu du modèle SMS transmis précédemment par le client. cette méthode contenait du codage dur, nous devons maintenant la changer en acquisition dynamique.

Exemple de contenu d'un modèle de message texte :

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

J'ai trouvé qu'il y avait un problème avec le contenu d'un tel modèle. Les paramètres variables du modèle sont directement exprimés en mots anglais, et dans le contenu de notre message texte, il peut parfois y avoir des mots anglais, je vais donc ajouter {} à tous les paramètres variables. La modification est la suivante :

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

Nous devons remplacer les paramètres variables dans le modèle SMS par les valeurs correspondant aux paramètres variables en fonction de l'objet passé par le client. Ensuite, nous devons d'abord analyser les informations sur la paire clé-valeur dans cet objet.

  /// 把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;
        }
Copier après la connexion

L'étape suivante consiste à faire correspondre le contenu du modèle de message texte via des expressions régulières.

  /// 多个匹配内容
        /// </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;
}
Copier après la connexion

De cette façon, l'objet transmis par le client est découplé de notre code d'analyse. L'objet transmis par le client ne dépend plus de l'implémentation de notre code, mais dépend du contenu du modèle dans notre table de données. .configuration.

J'ai écrit ces méthodes et je vais exécuter un test unitaire pour vérifier si cela a l'effet souhaité. Malheureusement, les tests unitaires ne sont pas du tout utilisés dans ce projet. Il n'y a aucun moyen de créer un. testez vous-même les unités

[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);
        }
    }
Copier après la connexion

En parlant de tests unitaires, je pense qu'ils ne sont pas utilisés dans de nombreuses entreprises pour de trop nombreuses raisons. Je pense aussi que si le business est simple, il n'est pas nécessaire d'écrire des tests unitaires. Trop d'entreprises entrepreneuriales en Chine sont très rapides sur leurs projets. Si l'on dit que l'écriture de tests unitaires ne prend pas de temps, c'est définitivement un mensonge. Quant à l'écriture de tests unitaires, elle peut améliorer l'efficacité du développement et réduire le taux de retravail. Personnellement, c'est difficile à dire, car même si vous n'écrivez pas de tests unitaires, vous pouvez toujours compenser. par bien d’autres moyens. Opinion personnelle, ne critiquez pas.

Ensuite, modifiez la méthode GetContent comme suit :

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;
        }
Copier après la connexion

(En plus : plaignons-nous du nom des variables précédentes, MessageContext messageContext et string messageContent, elles se ressemblent trop. Je les ai répétées à d'abord. J'ai fait une erreur lors de sa construction. Il est recommandé de ne pas utiliser de noms de variables similaires dans la même méthode pour éviter toute confusion, j'ai encore été trompé et j'étais insupportable, alors je l'ai renommé de manière décisive.) 🎜>


Il s'avère que le contrôleur appelle le code de logique métier directement comme ceci

MessageModuleBusiness message
ModuleBusiness = new MessageModuleBusiness()
Copier après la connexion
Cela dépend de l'implémentation de la classe spécifique, et nous savons que le spécifique est instable, l'abstraction est stable, nous devrions programmer pour les interfaces. Aujourd'hui, vous envoyez des messages texte, demain vous enverrez peut-être des e-mails ou ajouterez des enregistrements de journaux, etc.

public interface IMessageModuleBusiness
{
        /// <summary>
        /// 组装消息内容
        /// </summary>
        /// <param name="messageContext">动态参数对象</param>
        /// <returns>组装后的消息内容</returns>
        string GetContent(dynamic messageContext);
}
Copier après la connexion
Ensuite, le code appelant est modifié en :

private IMessageModuleBusiness message
ModuleBusiness = new MessageModuleBusiness();
Copier après la connexion
Le code final externalMerchantSendMessage est :

    /// 外部商户发送信息
        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);
            }
        }
Copier après la connexion
Dans ce cas, même s'il est appelé par réflexion ou IOC à l'avenir Il est également pratique de découpler à nouveau.


D'accord, grâce à cette reconstruction étape par étape, j'ai encapsulé les changements sans modifier la structure de la table d'origine et sans affecter les appels du client, lorsque les variables des paramètres du modèle du client. changement, il n'est pas nécessaire de changer le code, seul le contenu du modèle dans le tableau doit être modifié.

Souvenez-vous dune refactorisation de code .NET (Partie 2)

Lors du refactoring, c'est une très bonne habitude de dessiner des diagrammes de classes. La structure du code est claire en un coup d'œil.

Ce qui précède est le contenu d'une reconstruction de code .NET (Partie 2). Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois (www.php.cn) !


Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal