代码改变世界

使用委托,满足不同的场景,开放封闭原则

2010-05-16 18:08  CleverDeng  阅读(2161)  评论(7编辑  收藏  举报

委托是虾米

根绝国际惯例,先借用隐喻的强大威力说说委托是啥,委托:将自己的事务嘱托他人代为处理。那么计算机中的委托概念呢?大同小可。

在现实生活中,这样的场景天天都在发生。比如老王的项目快上线了,可是当月的报销少了通讯费的发票,这咋办了?不用急,把话费钱给小张,委托小张童鞋代缴,而小张是个好同志呀,不用打的,做公交车去。老王想起了上次小邓同学同样帮我代缴通讯费,几个站的路却玩享受坐的奔过去的。那么在程序的世界里是不是也有这种场景的映射呢?当然有,时时有,不然就没本篇博文了,本文通过Javascript的一个应用场景分享一次重构的心得。

JavaScript使用Ajax发表评论、留言

在我自己维护的Mr.d'Time个人博客里,用户互动的都是运行了Ajax技术,而Ajax的实现是利用了Jquery这个框架,那么我在开发的前期,是这样完成这2个功能的。(基本结构,具体实现略)

//文章评论

function mark(id)
{
   var userName=$("#txtname").val();
   var sendData="Action=mark&id="+id+"&username="+userName+"";
   SendPost(sendData);
}

//留言

function message()
{
   var userName=$("#txtname").val();
   var sendData="Action=message&username="+userName+"";
   SendPost(sendData);
}

function SendPost(content)
{
    jQuery.ajax({
     type: "GET",
     url: "demo.aspx",
     data: ""+content+"",
     cache: false,
     timeout: 20000,
     dataType: "text",
     error: function(xmlHttpRequest, error) {
         ShowInfo("热心提示:操作超时,请稍后使用...");
     },

     success: function(msg) {

        ShowInfo("热心提示:"+showmsg+"...");

     }

   });

   return false;
}

OK,这就是前期结构,看似很不错,代码的重复利用率也比较高,每个功能都只需要构造好发送的数据,统一利用SendPost()这个方法接口统一发出Ajax请求,然后将回传的数据显示出来。其实这个结构面对个性化的需求场景就难免力不从心了,因为我们可以看到这个结构的最后处理方式都是一致的。比如发表评论后需要及时看到更新的数据呢或发表留言需要及时看到更新的留言信息呢?

提升用户体验,重构、重构、再重构

有新的需求了,某日,一朋友在浏览我的博客时告诉我,评论发表后需要刷新才能看到我的评论了,体验不好哟。这个问题,我还是非常清楚的,但是由于原有结构不太愿意动手去修改,一直留到现在迟迟没动手,但最近在对博客的皮肤结构调整时,因此也动了重构的念头。那么中间就有了个选择方案的过程。第一个思考方案是这样的。(基本结构,具体实现略)

//文章评论

function mark(id)
{
   var userName=$("#txtname").val();
   var sendData="Action=mark&id="+id+"&username="+userName+"";
   SendPost(sendData);
}

//留言

function message()
{
   var userName=$("#txtname").val();
   var sendData="Action=message&username="+userName+"";
   SendPost(sendData);

}

function SendPost(content)
{
    $.ajax({
     type: "GET",
     url: "demo.aspx",
     data: ""+content+"",
     cache: false,
     timeout: 20000,
     dataType: "text",
     error: function(xmlHttpRequest, error) {
         ShowInfo("热心提示:操作超时,请稍后使用...");
     },

     success: function(msg) {

       var type=msg.split('^')[0];

       var showmsg=msg.split('^')[1];

        if("mark"==type)

       {

          ShowInfo("热心提示:发表评论成功...");

          $("#mark").html(msg);

          return false;

        }

        if("message"==type)

        {

           ShowInfo("热心提示:发表留言成功...");

           $("#message").html(msg);

           return false;

        }

     }

   });

   return false;
}

OK,这个想象的实现结构就如上面所描叙,对比第一种实现方式(初期的实现),不同之处在于回调方法中写了If判断实现不同的需求场景,同时还需要服务器端的回传数据按照一定格式。也许有人在想,恩,这个方式是不错,把变法都封装在发送请求的数据中(url链接字串中的参数)和回传的数据中,当初确实是这样想象的,但马上被否定了,一、原因是发表评论与获取最新的评论捆绑在一个方法请求里,也许某天我不需要发表评论后就立即看到最新的数据呢?二、如果以后有(顶、踩)等等类似的功能呢?难道每次的改动就需要加If判断吗?那我无法想象以后还有激情维护自己的这个博客了。好吧,那么再想想。怎么把变法的部分封装起来,使其对扩展开放,修改关闭呢?恩,NET中的委托在JavaScript中也能使用吗?这一想法一出,马上做了个Demo,运行效果不错。因此就有了第二种实现方式。

使用委托代理,满足执行过程相同,执行方式不同

根据前面的简叙,我们知道这个功能场景跟本文开始处举例的场景类似,大体执行的过程相同,但是执行方式不同。前面说过委托代理不同的同事去完成代缴通讯费,他们实现的方式截然不同。那么其实变法在于委托人(代理人)不同而已,真对发表评论和留言这2个功能场景,我们只需编写不同的回调方法,再次重构后的实现是这样的。(基本结构,具体实现略)

//文章评论

function mark(id)
{
   var userName=$("#txtname").val();
   var sendData="Action=mark&id="+id+"&username="+userName+"";
   SendPost(sendData,markcallback);
}

function markcallback(msg)

{

   ShowInfo("热心提示:发表评论成功...");

   $("#mark").html(msg);

}

//留言

function message()
{
   var userName=$("#txtname").val();
   var sendData="Action=message&username="+userName+"";
   SendPost(sendData,messagecallback);

}

function messagecallbak(msg)

{

   ShowInfo("热心提示:发表留言成功...");

   $("#message").html(msg);

}

function SendPost(content,m)
{
    $.ajax({
     type: "GET",
     url: "demo.aspx",
     data: ""+content+"",
     cache: false,
     timeout: 20000,
     dataType: "text",
     error: function(xmlHttpRequest, error) {
         ShowInfo("热心提示:操作超时,请稍后使用...");
     },

     success: function(msg) {

        m(msg);

     }

   });

   return false;
}

OK,通过上面这个是用委托的重构,我们能够发现,统一的发出Ajax请求的方法在回调方法时已经没有If判断,而只是充当了代理者的身份,二具体的实现却根据具体的场景。因此到此我已经很满意这个结构了,比如我日后需要个(顶,踩)的功能,只需要扩展顶与踩的方法和具体的回调方法。而不必去修改统一的发出Ajax请求的接口。

总结

通过本文的描叙一个简单的应用场景,一步一步的重构满足以知的需求,正如上文所说,如果我们以后需要扩展一个(顶、踩)的功能呢,同样只也需定义好回调的方法,同样使用这套统一的Ajax的请求接口以满足需求,最后我们发现使用委托代理的方法对比之前的实现或构想更为灵活,是否刚好印证了前辈们所说的向修改封闭,向扩展开放的的开放封闭原则了。欢迎分享您的观点,在交流中成长。