zoukankan      html  css  js  c++  java
  • 运用Composite模式构造JSON

      Json是如今流行的Ajax或Service数据交换格式,.NET使用DataContractJsonSerializer(System.Runtime.Serialization.Json命名空间下),可以很方便地在json字符串和实体对象间转换。

      在Restful WCF服务站点上,更无须写代码序列化Json。服务默认以xml形式返回结果,但如果Web请求头信息中的Accept属性为application/json,客户端得到的就是以json格式序列化了结果。

      客户端用jquery实现很简单,只要调用ajax函数时,设置dataType:’json’就可以了。

      客户端也可以发送json到让服务处理,只要把请求头的ContentType设为text/json(jquery的ajax函数也有这个属性),服务会自动将请求内容反序列化为实体。

      然而很多情况下,我们输出的json不是标准的实体集合,可能只输出其中个别属性,或者掺点别的东西,比如分页查询,我们要告诉客户返回的结果集是第几页,一共有多少页,这样的json还得我们自己通过代码输出。这就比较烦了,业务复杂点没办法,但写那些单引双引,花括号方括号,经常还得转义,可一点不好玩。比如一个最简单的实体:

    var sb = new StringBuilder("[");
    foreach (var user in lstUser)
    {
        sb.AppendFormat("{{'name':'{0}','email':'{1}'}},",user.Name,user.Email);
    }
    sb.Remove(sb.Length - 1, 1);
    sb.Append("]");
    

      能一遍写对这段代码的人,绝非等闲之辈。偶打草稿时还写错了。相形之下,json的老大哥xml就给力多了,因为里面所有操作都可以通过对象,比如XAttribute、XText、XComment等。

    class Program
    {
        static void Main()
        {
            var lstUser = new List<User>{
                new User { Name = "潘金莲",  Email="pjl@sh.com"},
                new User { Name = "武松",  Email="ws@sh.com"},
                new User { Name = "西门庆",  Email="xmq@sh.com"}               
            };
    
            var xe = new XElement("Users",
                from u in lstUser
                select new XElement("User",
                    new XAttribute("name", u.Name),
                    new XAttribute("email", u.Email)));
    
            Console.WriteLine(xe);
            Console.ReadLine();
        }
    
        class User
        {
            public string Name { get; set; }
            public string Email { get; set; }
        }
    }
    

      优雅的5行代码,把潘金莲和她最重要的两个男人潇洒地绑在一起。写Json也能如此优雅吗,完全可以,其实我们早就有了Json.Net,重量级拳手,我感觉,玩我们日常的应用如同高射炮打麻雀,还不如做个弹弓来的实惠。

      仿照XNode,定义了几个Json对象类型:

    /// <summary>
    /// 表示json数组
    /// </summary>
    class JArray : JElement
    {
        public JArray(params object[] array)
        {
            this.Elements = array.Select(o =>
            {
                var element = o as JElement;
                if (element == null) return new JElement(o);
                else return element;
            }).ToList();
        }
    
        public List<JElement> Elements { get; set; }
    
        public override string ToString()
        {
            return "[" + String.Join(",", this.Elements) + "]";
        }
    }
    
    /// <summary>
    /// 表示json实体对象
    /// </summary>
    class JEntity : JElement
    {
        public JEntity(params JProperty[] properties)
        {        
            this.Value = properties.ToList();
        }
    
        public List<JProperty> Properties { get { return this.Value as List<JProperty>; } }
    
        public override string ToString()
        {
            return "{" + String.Join(",", this.Properties) + "}";
        }
    }
    
    /// <summary>
    /// 表示一个json实体的属性键值对
    /// </summary>
    class JProperty 
    {
        public JProperty(string name, object value)
        {
            this.Name = name;
    
            var element = value as JElement;
            if (element == null) element = new JElement(value);
            this.Value = element;
        }
    
        public string Name { get; set; }
    
        public JElement Value { get; set; }
    
        public override string ToString()
        {
            return "'" + Name + "':'" + Value + "'";
        }
    }
    
    /// <summary>
    /// 表示基本的json元素
    /// </summary>
    class JElement
    {
        public JElement() { }
    
        public JElement(object value)
        {
            var array = value as System.Collections.IEnumerable;
    
            if (array != null && !(value is string))
            {
                this.Value = new JArray(array.Cast<object>().ToArray());
            }
            else this.Value = value;
        }
    
        public object Value { get; set; }
    
        public override string ToString()
        {
            var type = Value.GetType();
            if (type.IsPrimitive)
            {
                if (type == typeof(int) || type == typeof(double)) return Value.ToString();
            }
    
            return "'" + Value + "'";
        }
    }
    

      然后,我们就可以这么写json了,看,与输出xml的写法很相似吧:

    var json = new JArray(
        (from u in lstUser
        select new JEntity(
            new JProperty("name", u.Name),
            new JProperty("email", u.Email))).ToArray());
    
    Console.WriteLine(json);
    

      话说json本来就是轻量级的数据交换格式,轻量级格式也应该用轻量方法处理,并且还要能重用,最重要的是一目了然,大家可以考虑下这种方式。对JArray等几个构造函数,还待进一步改进。

      经过最近研究,发现这种优雅的方式json构造方式,莫非是暗合了江湖至高无上,OOP兵法23条中的Composite模式(《.Net设计模式》第九章)?无意中得窥至尊宝典之道,哇呀妙哉!

      最近还发现了,json还有个小弟,唤作jsonp的东东,火星了,原来就是BingMap API的脚本加载方式,经常使用还朦朣不觉。

      现在轮到自己写服务器端,不想破坏WCF自动转换的优美,想用输出替换的方式,但设置Resonse.Filter(参考)真麻烦,Response.OutputStream又只能写不能读。只好响应全局事件,在正文开始前先写入客户端回调的函数名和一个括号,在正文输出结束后添上另一个括号。虽然早就知道,可每次写起来,偶的心还是隐隐作疼,纠结一番。

  • 相关阅读:
    WUST Online Judge
    WUST Online Judge
    WUST Online Judge
    WUST Online Judge
    写在前面
    一丶Python简介
    七丶Python字典
    六丶Python列表操作
    五丶Python列表丶元组丶字典
    四丶Python运算符
  • 原文地址:https://www.cnblogs.com/XmNotes/p/2146355.html
Copyright © 2011-2022 走看看