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

黄舟
Libérer: 2017-02-06 14:37:00
original
1207 Les gens l'ont consulté

Exigence : c'est le cas. Pour développer un modèle d'envoi de messages texte, différents clients peuvent utiliser différents modèles, et les paramètres variables utilisés par différents clients sont également différents.


En cas d'urgence, une fonction de modèle de message texte pour l'envoi de messages texte a été complétée en ligne. Le tableau des modèles de message texte a également été créé et un nouvel enregistrement a été ajouté. à table. Il me suffit de créer une interface pour ajouter, supprimer, modifier et vérifier des modèles de messages texte. Il semble que ma tâche soit assez simple. Un conducteur expérimenté devrait savoir que je me suis retrouvé dans le pétrin.


L'image ci-dessous montre la table créée à l'origine

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

Le script de création SQL est le suivant :

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

Avant cela, une interface API d'envoi de messages texte a été développée pour que les clients puissent appeler. En d'autres termes, l'appelant (client) ne modifiera pas le code, seulement moi. Même si je suis extrêmement réticent à entreprendre des tâches à moitié terminées, je n'ai d'autre choix que de recommencer toutes les tâches de développement à partir de zéro.


Le code de classe d'entité est le suivant :

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

Classe DOT :

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

Voici le code précédent, le code de la classe d'entité commerciale MessageModuleBusiness.cs est le suivant :

public class MessageModuleBusiness : GenericRepository<Model.MessageModule>
    {
        private UnitOfWork.UnitOfWork unitOfWork = new UnitOfWork.UnitOfWork();
        /// 获取模版内容
        public string GetContent(MessageContext messageContext)
        {
            string messageContent = "";
            string TypeCode = string.IsNullOrEmpty(messageContext.serviceCode) ? "001" : messageContext.serviceCode;
            try
            {
                var Module = unitOfWork.MessageModule.Get(c => c.Type == messageContext.channel && c.TypeNo == TypeCode).FirstOrDefault();
                //Content的内容:【一应生活】您有一件单号为expressNumbers company,
                已到communityName收发室,请打开一应生活APP“收发室”获取取件码进行取件。点击下载http://a.app.qq.com/o/simple.jsp?pkgname=com.ening.life
                if (!string.IsNullOrEmpty(Module.Content))
                {
                    var content = Module.Content;
                    content = content.Replace("company", messageContext.company);
                    content = content.Replace("expressNumbers", messageContext.expressNumbers);
                    content = content.Replace("communityName", messageContext.communityName);
                    content = content.Replace("Id", messageContext.Id);
                    content = content.Replace("receiveTime", messageContext.receiveTime);
                    content = content.Replace("fetchCode", messageContext.fetchCode);
                    messageContent = content;
                }
                return messageContent;
            }
            catch (Exception ex) {}
            return "";
        } 
        #endregion
}
Copier après la connexion

Classe MessageContext, c'est un objet d'entité transmis et appelé par le client. Il existe de nombreuses variables de balises dynamiques similaires aux messages texte dans l'objet.

public class MessageContext{
        /// 手机号码
        public string phone { get; set; }
        /// 发送信息
        public string message { get; set; }
        /// 签名
        public string sign { get; set; }
        /// 渠道
        public string channel { get; set; }
        /// 内容
        public string content { get; set; }
        /// 取件码
        public string fetchCode { get; set; }
        /// 快递公司
        public string company { get; set; }
        /// 快递单号
        public string expressNumbers { get; set; }
        /// 社区名称
        public string communityName { get; set; }
        /// 到件时间
        public string receiveTime { get; set; }
        /// 序号
        public string Id { get; set; }
        /// 业务代码
        public string serviceCode { get; set; }
    }
Copier après la connexion

Méthode du contrôleur externalMerchantSendMessage, qui est destinée aux appels externes

    /// 外部商户发送信息
        public ActionResult externalMerchantSendMessage(MessageContext param)
        {
            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);
        }
Copier après la connexion

Ce qui précède sont les fonctions que j'ai implémentées avant de recevoir la tâche de développement. Il semble que ma tâche soit assez simple, mais de nombreuses années d'expérience en développement me disent que cela doit être refactorisé maintenant et que je crée simplement une interface pour ajouter, supprimer, modifier et vérifier des modèles SMS. les gens de maintenance à l’avenir deviendront certainement fous.


Voyez-vous un problème ?


Cette méthode d'interface externalMerchantSendMessage est appelée pour tous les clients, et différents clients utilisent différents modèles de SMS, et différents modèles ont différents paramètres variables. Désormais, tous les paramètres variables sont encapsulés dans la classe MessageContext. Le problème est que nous ne pouvons pas déterminer tous les paramètres variables à la fois et les conserver inchangés.


Ainsi, c'est-à-dire qu'une fois que des paramètres variables doivent être ajoutés, le code de la classe MessageContext doit être modifié et le code de la méthode GetContent est difficile à modifier. codé et doit être modifié en conséquence. Cela forme un cycle, ajoutant constamment des paramètres variables, changeant constamment le code et publiant constamment des versions d'interface...


Quand j'ai assez de temps, je naturellement Si vous êtes un programmeur discipliné, puis commencez à refactoriser.


Avant le refactoring, ce qui me vient à l'esprit, ce ne sont pas divers modèles de conception, mais les principes de base de la conception orientée objet. Divers modèles de conception sont comme diverses routines ou mouvements d'arts martiaux. Les pratiquants d'arts martiaux devraient être comme Zhang Wuji pratiquant l'épée de Tai Chi, apprendre d'abord diverses routines, puis oublier toutes les routines pour les maîtriser.


Parce que les mouvements sont morts, les gens sont vivants et que chaque mouvement a ses défauts, il n'y a pas de mouvement sûr du tout, tout comme il n'y a pas de modèle de conception universel, n'importe quelle conception Tous les modèles ont des défauts.


L'idée centrale de la conception orientée objet est d'encapsuler les changements, alors trouvez d'abord les points de changement. À partir de l'analyse ci-dessus, nous avons découvert le point de changement, à savoir les paramètres variables dans le modèle SMS, et ces paramètres variables sont transmis par l'appelant du client, et les variables paramètres transmises par différents clients peuvent être différentes.


Voyons d'abord ce qui est transmis par le client ? Jetons un coup d'œil au code d'appel du client. Il existe deux méthodes d'appel : Get et Post.

function sendMsg() {
            //var appParam ="phone=15914070649&sign=78a7ce797cf757916c2c7675b6865b54&channel=weijiakeji&content=&fetchCode=1
&company=%E9%A1%BA%E4%B8%B0%E5%BF%AB%E9%80%92&expressNumbers=123456&communityName=%E9%95%BF%E5%9F%8E%E4%B8%80%E8%8A%B1%E5%9B%AD&receiveTime=5&Id=1231";
            //Get("/Message/externalMerchantSendMessage?" + appParam, {});

            var data = {
                "phone": "15914070649", "sign": "78a7ce797cf757916c2c7675b6865b54", "channel": "weijiakeji",
                "fetchCode": 1, "company": "%E9%A1%BA%E4%B8%B0%E5%BF%AB%E9%80%92", "Id": "1231"
            };
            Post(&#39;/Message/externalMerchantSendMessage&#39;, data);
        }
        //WebAPI Post方法
        function Post(url, data) {
            $.ajax({
                url: url,
                contentType: "application/json",
                type: "POST",
                dataType: "json",
                async: true,
                cache: false,
                data: JSON.stringify(data),
                success: function (response) {
                    $(&#39;#response&#39;).text(JSON.stringify(response));
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    alert(textStatus);
                }
            });
        };
        //// WebApi Get方法
        function Get(url, data) {
            $.ajax({
                url: url,
                contentType: "application/json",
                type: "GET",
                dataType: "json",
                async: true,
                cache: false,
                //data: JSON.stringify(data),
                success: function (response) {
                    $(&#39;#response&#39;).text(JSON.stringify(response));
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    alert(textStatus);
                }
            });
        };
Copier après la connexion

On peut voir que ce que le client transmet est une collection de paires clé-valeur, qui est un objet au format JSON. D'après le code précédent bool isAuth = authModelBusiness.isAuth(param.channel, param.phone, param.sign);, on peut analyser qu'il existe trois paramètres que tous les clients appelants doivent transmettre, à savoir : canal, téléphone, signe , Les autres paramètres sont les paramètres variables et les valeurs des paramètres du modèle SMS.


Ensuite, le paramètre dans la méthode externalMerchantSendMessage(MessageContext param) est un objet variable. N'existe-t-il pas une dynamique en C# 4.0 utilisée pour décrire les objets mutables ?

Ensuite, la première étape consiste à modifier le type de paramètre entrant. Il s'agissait auparavant d'un MessageContext fortement typé codé en dur. Désormais, il ne repose plus sur ce type, mais sur l'analyse dynamique. Modifiez le code de la méthode externalMerchantSendMessage comme suit. :

:

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

DynamicJsonConverter est utilisé pour convertir des chaînes JSON en objets Object Le code est le suivant :

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Web.Script.Serialization;

public sealed class DynamicJsonConverter : JavaScriptConverter
{
    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        if (dictionary == null)
            throw new ArgumentNullException("dictionary");

        return type == typeof(object) ? new DynamicJsonObject(dictionary) : null;
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override IEnumerable<Type> SupportedTypes
    {
        get { return new ReadOnlyCollection<Type>(new List<Type>(new[] { typeof(object) })); }
    }
  #region Nested type: DynamicJsonObject

    private sealed class DynamicJsonObject : DynamicObject
    {
        private readonly IDictionary<string, object> _dictionary;

        public DynamicJsonObject(IDictionary<string, object> dictionary)
        {
            if (dictionary == null)
                throw new ArgumentNullException("dictionary");
            _dictionary = dictionary;
        }

        public override string ToString()
        {
            var sb = new StringBuilder("{");
            ToString(sb);
            return sb.ToString();
        }

        private void ToString(StringBuilder sb)
        {
            var firstInDictionary = true;
            foreach (var pair in _dictionary)
            {
                if (!firstInDictionary)
                    sb.Append(",");
                firstInDictionary = false;
                var value = pair.Value;
                var name = pair.Key;
                if (value is string)
                {
                    sb.AppendFormat("{0}:\"{1}\"", name, value);
                }
                else if (value is IDictionary<string, object>)
                {
                    new DynamicJsonObject((IDictionary<string, object>)value).ToString(sb);
                }
                else if (value is ArrayList)
                {
                    sb.Append(name + ":[");
                    var firstInArray = true;
                    foreach (var arrayValue in (ArrayList)value)
                    {
                        if (!firstInArray)
                            sb.Append(",");
                        firstInArray = false;
                        if (arrayValue is IDictionary<string, object>)
                            new DynamicJsonObject((IDictionary<string, object>)arrayValue).ToString(sb);
                        else if (arrayValue is string)
                            sb.AppendFormat("\"{0}\"", arrayValue);
                        else
                            sb.AppendFormat("{0}", arrayValue);

                    }
                    sb.Append("]");
                }
                else
                {
                    sb.AppendFormat("{0}:{1}", name, value);
                }
            }
            sb.Append("}");
        }
Copier après la connexion

Ce qui précède est le contenu d'un. Reconstruction du code .NET (Partie 1), plus Pour le contenu associé, 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