话说js设计模式有关的书籍有Ross Harmes / Dustin Diaz 的《Javascript设计模式》,Stoyan Stefanov的《JavaScript Patterns》,Addy Osmani的《Learning JavaScript Design Patterns》。
第一本很早就出来了,比较古老,基本上内容就是,js模拟面向对象语言,再把面向对象的设计模式套进来。
话说,设计模式是一种思想,面向对象语言,函数式语言都能以自己的方式演绎。
第二本,第三本就比较实在了,不那么崇拜面向对象了,虽然还是有点面向对象。
设计模式的入门书国人写的《大话设计模式》,很受用。这本书代码用C#演绎。
于是,决定把那本书的代码用javascript语言演绎,且用里面的设计模式思想。
今天就来说说策略模式吧。
原文是写,商场收银软件的实现。正常收费,打折收费,满xx返xx。
符合现实情况。产品人员,动不动跑过来说,有新需求,来来,给哥加个新功能。
面对不断变化和增加的需求,如何使自己的原先代码改动成本更小,这时候设计模式派上用场了。
话说,我实在看不出来策略模式和简单工厂模式有啥区别,因为我觉得它们都是同样的过程产生的模式。
直到,看到,后面,说,用简单工厂模式,客户端要认识两个类;用策略模式和简单工厂模式结合,客户端只认识一个类。
我顿时被雷到了。外焦里嫩了。
我觉得设计模式的表现,就是改写编程语言的默认调用方式。
至于各种模式,所展现的思想,都能以一个过程展示。这就是万变不离其宗吧。
好了,下面代码展示我的策略模式,其中还有函数式写法。
只要脑子里想着一个原则,把重复抽象出来,大重复基于小重复,应该就能写出和设计模式媲美的代码了,嘻嘻:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>策略模式</title> <script type="text/javascript">
// 打折收费,基于正常收费;满多少返多少收费,基于正常收费;打折收费结合满多少返多少收费,基于你懂的。 // 正常收费 function cash_normal(price_arg,num_arg) { return price_arg * num_arg; } // 打折收费 function cash_rebate(money_arg,rebate_arg){ return money_arg * rebate_arg; } // 满xx返xx function cash_return(money_input_arg,money_condition_arg, money_return_arg){ if(money_input_arg > money_condition_arg){ return money_input_arg - money_return_arg; } else{ return money_input_arg; } } // function cash_normal_rebate(price_arg, num_arg, rebate_arg){ return cash_rebate(cash_normal(price_arg,num_arg),rebate_arg); } function cash_normal_rebate_return(price_arg, num_arg, rebate_arg, money_condition_arg, money_return_arg){ return cash_return(cash_normal_rebate(price_arg,num_arg,rebate_arg),money_condition_arg,money_return_arg) } var number = 10; var price = 10; console.log("打八折:买"+number+"个,"+price+"元的东西"+cash_normal_rebate(number,price,0.8)); console.log("打八折,满50返10元:"+cash_normal_rebate_return(price,number,0.8,50,10)); // 函数式写法 function tao(){ return tao; } function cash_normal2(price_arg,num_arg){ return function(handle_func){ var total_money = price_arg * num_arg; if(handle_func){ return handle_func(total_money); } else{ return tao; } }; } function crsh_rebate_factory(rebate_arg){ return function(total_money){ // var total_money = rebate_arg*total_money; return function(handle_func){ var discount_money = rebate_arg * total_money; if(handle_func){ return handle_func(discount_money,rebate_arg); } else{ return tao; } }; }; } function show_money(total_money,rebate_arg){ return function(handle_func){ console.log("函数式写法,乘以"+rebate_arg+":" + total_money); if(handle_func){ return handle_func(total_money); } else{ return tao; } } } cash_normal2(10,10)(crsh_rebate_factory(0.8))(show_money)(); </script> </head> <body> </body> </html>
函数式写法有意思的地方在于,参数是函数,返回的是函数。完成一个任务,只要不断调用函数就行了,是横向。
而主流抽象方法是,大函数,用到小函数的话,得把小函数的参数,放进大函数的参数列表里面。
设计模式里有一个依赖倒转原则,对于,大函数依赖小函数,不是非常认可。无论大函数,还是小函数都要依赖抽象。
什么是抽象?对于面向对象来说,子类实例可以被父类创建。父类就是子类实例的抽象。
当然,更抽象的是,产品经理的需求和文档。