@@ -488,132 +488,129 @@ JavaScript没有类,所以一字一句地说单例的定义并没有什么意
488
488
489
489
装饰器模式的第二种实现方式更简单一些,并且没有引入继承。装饰的方法也会简单。所有的工作都由“同意”被装饰的方法来做。在这个示例实现中,` getPrice() ` 是唯一被允许装饰的方法。如果你想有更多可以被装饰的方法,那遍历装饰器列表的工作就需要由每个方法重复去做。但是,这可以很容易地被抽象到一个辅助方法中,给它传一个方法然后使这个方法“可被装饰”。如果这样实现的话,` decorators_list ` 属性就应该是一个对象,它的属性名字是方法名,值是装饰器对象的数组。
490
490
491
- <a name =" a13 " ></a >
492
491
## 策略模式
493
492
494
493
策略模式允许在运行的时候选择算法。你的代码的使用者可以在处理特定任务的时候根据即将要做的事情的上下文来从一些可用的算法中选择一个。
495
494
496
- 使用策略模式的一个例子是解决表单验证的问题。你可以创建一个validator对象,有一个validate() 方法。这个方法被调用时不用区分具体的表单类型,它总是会返回同样的结果——一个没有通过验证的列表和错误信息。
495
+ 使用策略模式的一个例子是解决表单验证的问题。你可以创建一个 ` validator ` 对象,有一个 ` validate() ` 方法。这个方法被调用时不用区分具体的表单类型,它总是会返回同样的结果——一个没有通过验证的列表和错误信息。
497
496
498
- 但是根据具体的需要验证的表单和数据,你代码的使用者可以选择进行不同类别的检查。你的validator选择最佳的策略来处理这个任务 ,然后将具体的数据检查工作交给合适的算法去做。
497
+ 但是根据具体的需要验证的表单和数据,你代码的使用者可以选择进行不同类别的检查。你的 ` validator ` 选择最佳的策略来处理这个任务 ,然后将具体的数据检查工作交给合适的算法去做。
499
498
500
- <a name =" a14 " ></a >
501
499
### 数据验证示例
502
500
503
501
假设你有一个下面这样的数据,它可能来自页面上的一个表单,你希望验证它是不是有效的数据:
504
502
505
503
var data = {
506
- first_name: "Super",
507
- last_name: "Man",
508
- age: "unknown",
509
- username: "o_O"
504
+ first_name: "Super",
505
+ last_name: "Man",
506
+ age: "unknown",
507
+ username: "o_O"
510
508
};
511
509
512
- 对这个例子中的validator ,它需要知道哪个是最佳策略,因此你需要先配置它,给它设定好规则以确定哪些是有效的数据。
510
+ 对这个例子中的 ` validator ` 而言 ,它需要知道哪个是最佳策略,因此你需要先配置它,给它设定好规则以确定哪些是有效的数据。
513
511
514
512
假设你不需要姓,名字可以接受任何内容,但要求年龄是一个数字,并且用户名只允许包含字母和数字。配置可能是这样的:
515
513
516
514
validator.config = {
517
- first_name: 'isNonEmpty',
518
- age: 'isNumber',
519
- username: 'isAlphaNum'
515
+ first_name: 'isNonEmpty',
516
+ age: 'isNumber',
517
+ username: 'isAlphaNum'
520
518
};
521
519
522
- 现在validator对象已经有了用来处理数据的配置,你可以调用validate() 方法,然后将任何验证错误打印到控制台上 :
520
+ 现在 ` validator ` 对象已经有了用来处理数据的配置,你可以调用 ` validate() ` 方法,然后将验证错误打印到控制台上 :
523
521
524
522
validator.validate(data);
525
523
if (validator.hasErrors()) {
526
- console.log(validator.messages.join("\n"));
524
+ console.log(validator.messages.join("\n"));
527
525
}
528
526
529
527
它可能会打印出这样的信息:
530
528
531
529
Invalid value for *age*, the value can only be a valid number, e.g. 1, 3.14 or 2010
532
530
Invalid value for *username*, the value can only contain characters and numbers, no special symbols
533
531
534
- 现在我们来看一下这个validator是如何实现的。所有可用的用来检查的逻辑都是拥有一个validate() 方法的对象,它们还有一行辅助信息用来显示错误信息:
532
+ 现在我们来看一下这个 ` validator ` 是如何实现的。所有可用的用来验证的逻辑都是拥有一个 ` validate() ` 方法的对象,它们还有一行辅助信息用来显示错误信息:
535
533
536
- // checks for non-empty values
534
+ // 验证空值
537
535
validator.types.isNonEmpty = {
538
- validate: function (value) {
539
- return value !== "";
540
- },
541
- instructions: "the value cannot be empty"
536
+ validate: function (value) {
537
+ return value !== "";
538
+ },
539
+ instructions: "the value cannot be empty"
542
540
};
543
541
544
- // checks if a value is a number
542
+ // 验证数字
545
543
validator.types.isNumber = {
546
- validate: function (value) {
547
- return !isNaN(value);
548
- },
549
- instructions: "the value can only be a valid number, e.g. 1, 3.14 or 2010"
544
+ validate: function (value) {
545
+ return !isNaN(value);
546
+ },
547
+ instructions: "the value can only be a valid number, e.g. 1, 3.14 or 2010"
550
548
};
551
549
552
- // checks if the value contains only letters and numbers
550
+ // 验证是否只包含字母和数字
553
551
validator.types.isAlphaNum = {
554
- validate: function (value) {
555
- return !/[^a-z0-9]/i.test(value);
556
- },
557
- instructions: "the value can only contain characters and numbers, no special symbols"
552
+ validate: function (value) {
553
+ return !/[^a-z0-9]/i.test(value);
554
+ },
555
+ instructions: "the value can only contain characters and numbers, no special symbols"
558
556
};
559
557
560
- 最后,validator对象的核心是这样的 :
558
+ 最后,` validator ` 对象的核心是这样的 :
561
559
562
560
var validator = {
563
561
564
- // all available checks
565
- types: {},
566
-
567
- // error messages in the current
568
- // validation session
569
- messages: [],
570
-
571
- // current validation config
572
- // name: validation type
573
- config: {},
574
-
575
- // the interface method
576
- // `data` is key => value pairs
577
- validate: function (data) {
578
-
579
- var i, msg, type, checker, result_ok;
580
-
581
- // reset all messages
582
- this.messages = [];
583
- for (i in data) {
584
-
585
- if (data.hasOwnProperty(i)) {
586
-
587
- type = this.config[i];
588
- checker = this.types[type];
589
-
590
- if (!type) {
591
- continue; // no need to validate
592
- }
593
- if (!checker) { // uh-oh
594
- throw {
595
- name: "ValidationError",
596
- message: "No handler to validate type " + type
597
- };
598
- }
599
-
600
- result_ok = checker.validate(data[i]);
601
- if (!result_ok) {
602
- msg = "Invalid value for *" + i + "*, " + checker.instructions;
603
- this.messages.push(msg);
604
- }
605
- }
606
- }
607
- return this.hasErrors();
608
- },
609
-
610
- // helper
611
- hasErrors: function () {
612
- return this.messages.length !== 0;
613
- }
562
+ // 所有可用的验证类型
563
+ types: {},
564
+
565
+ // 本次验证所有的错误消息
566
+ messages: [],
567
+
568
+ // 本次验证的配置,格式为:
569
+ // name: validation type
570
+ config: {},
571
+
572
+ // 接口方法
573
+ // `data` 是名值对
574
+ validate: function (data) {
575
+
576
+ var i, msg, type, checker, result_ok;
577
+
578
+ // 重置所有的错误消息
579
+ this.messages = [];
580
+ for (i in data) {
581
+
582
+ if (data.hasOwnProperty(i)) {
583
+
584
+ type = this.config[i];
585
+ checker = this.types[type];
586
+
587
+ if (!type) {
588
+ continue; // 不需要验证
589
+ }
590
+ if (!checker) { // 没有对应的验证类型
591
+ throw {
592
+ name: "ValidationError",
593
+ message: "No handler to validate type " + type
594
+ };
595
+ }
596
+
597
+ result_ok = checker.validate(data[i]);
598
+ if (!result_ok) {
599
+ msg = "Invalid value for *" + i + "*, " + checker.instructions;
600
+ this.messages.push(msg);
601
+ }
602
+ }
603
+ }
604
+ return this.hasErrors();
605
+ },
606
+
607
+ // 辅助方法
608
+ hasErrors: function () {
609
+ return this.messages.length !== 0;
610
+ }
614
611
};
615
612
616
- 如你所见,validator对象是通用的 ,在所有的需要验证的场景下都可以保持这个样子。改进它的办法就是增加更多类型的检查。如果你将它用在很多页面上,每快你就会有一个非常好的验证类型的集合。然后在每个新的使用场景下你需要做的仅仅是配置validator然后调用validate() 方法。
613
+ 如你所见,` validator ` 对象是通用的 ,在所有的需要验证的场景下都可以保持这个样子。改进它的办法就是增加更多类型的检查。如果你将它用在很多页面上,那么很快你就会有一个非常好的验证类型的集合。然后在新的使用场景下使用时你需要做的仅仅是配置 ` validator ` 然后调用 ` validate() ` 方法。
617
614
618
615
<a name =" a15 " ></a >
619
616
## 外观模式
@@ -632,35 +629,35 @@ JavaScript没有类,所以一字一句地说单例的定义并没有什么意
632
629
这是两个有不同目的的相互独立的方法,他们也应该被保持独立,但与此同时,他们也经常被一起调用。所以为了不在应用中到处重复调用这两个方法,你可以创建一个外观方法来调用它们:
633
630
634
631
var myevent = {
635
- // ...
636
- stop: function (e) {
637
- e.preventDefault();
638
- e.stopPropagation();
639
- }
640
- // ...
632
+ // ...
633
+ stop: function (e) {
634
+ e.preventDefault();
635
+ e.stopPropagation();
636
+ }
637
+ // ...
641
638
};
642
639
643
640
外观模式也适用于一些浏览器脚本的场景,即将浏览器的差异隐藏在一个外观方法下面。继续前面的例子,你可以添加一些处理IE中事件API的代码:
644
641
645
642
var myevent = {
646
- // ...
647
- stop: function (e) {
648
- // others
649
- if (typeof e.preventDefault === "function") {
650
- e.preventDefault();
651
- }
652
- if (typeof e.stopPropagation === "function") {
653
- e.stopPropagation();
654
- }
655
- // IE
656
- if (typeof e.returnValue === "boolean") {
657
- e.returnValue = false;
658
- }
659
- if (typeof e.cancelBubble === "boolean") {
660
- e.cancelBubble = true;
661
- }
662
- }
663
- // ...
643
+ // ...
644
+ stop: function (e) {
645
+ // others
646
+ if (typeof e.preventDefault === "function") {
647
+ e.preventDefault();
648
+ }
649
+ if (typeof e.stopPropagation === "function") {
650
+ e.stopPropagation();
651
+ }
652
+ // IE
653
+ if (typeof e.returnValue === "boolean") {
654
+ e.returnValue = false;
655
+ }
656
+ if (typeof e.cancelBubble === "boolean") {
657
+ e.cancelBubble = true;
658
+ }
659
+ }
660
+ // ...
664
661
};
665
662
666
663
外观模式在做一些重新设计和重构工作时也很有用。当你想用一个不同的实现来替换某个对象的时候,你可能需要工作相当长一段时间(一个复杂的对象),与此同时,一些使用这个新对象的代码也在被同步编写。你可以先想好新对象的API,然后使用新的API创建一个外观方法在旧的对象前面。使用这种方式,当你完全替换到旧的对象的时候,你只需要修改少量客户代码,因为新的客户代码已经是在使用新的API了。
@@ -852,48 +849,48 @@ proxy对象创建了一个队列来收集50ms之内接受到的视频ID,然后
852
849
下面是proxy对象的代码:
853
850
854
851
var proxy = {
855
- ids: [],
856
- delay: 50,
857
- timeout: null,
858
- callback: null,
859
- context: null,
860
- makeRequest: function (id, callback, context) {
861
- // add to the queue
862
- this.ids.push(id);
863
-
864
- this.callback = callback;
865
- this.context = context;
866
-
867
- // set up timeout
868
- if (!this.timeout) {
869
- this.timeout = setTimeout(function () {
870
- proxy.flush();
871
- }, this.delay);
872
- }
873
- },
874
- flush: function () {
875
-
876
- http.makeRequest(this.ids, "proxy.handler");
877
-
878
- // clear timeout and queue
879
- this.timeout = null;
880
- this.ids = [];
881
-
882
- },
883
- handler: function (data) {
884
- var i, max;
885
-
886
- // single video
887
- if (parseInt(data.query.count, 10) === 1) {
888
- proxy.callback.call(proxy.context, data.query.results.Video);
889
- return;
890
- }
891
-
892
- // multiple videos
893
- for (i = 0, max = data.query.results.Video.length; i < max; i += 1) {
894
- proxy.callback.call(proxy.context, data.query.results.Video[i]);
895
- }
896
- }
852
+ ids: [],
853
+ delay: 50,
854
+ timeout: null,
855
+ callback: null,
856
+ context: null,
857
+ makeRequest: function (id, callback, context) {
858
+ // add to the queue
859
+ this.ids.push(id);
860
+
861
+ this.callback = callback;
862
+ this.context = context;
863
+
864
+ // set up timeout
865
+ if (!this.timeout) {
866
+ this.timeout = setTimeout(function () {
867
+ proxy.flush();
868
+ }, this.delay);
869
+ }
870
+ },
871
+ flush: function () {
872
+
873
+ http.makeRequest(this.ids, "proxy.handler");
874
+
875
+ // clear timeout and queue
876
+ this.timeout = null;
877
+ this.ids = [];
878
+
879
+ },
880
+ handler: function (data) {
881
+ var i, max;
882
+
883
+ // single video
884
+ if (parseInt(data.query.count, 10) === 1) {
885
+ proxy.callback.call(proxy.context, data.query.results.Video);
886
+ return;
887
+ }
888
+
889
+ // multiple videos
890
+ for (i = 0, max = data.query.results.Video.length; i < max; i += 1) {
891
+ proxy.callback.call(proxy.context, data.query.results.Video[i]);
892
+ }
893
+ }
897
894
};
898
895
899
896
了解代理模式后就在只简单地改动一下原来的代码的情况下,将多个web service请求合并为一个。
0 commit comments