1
+ // 单一职责原则 SRP
2
+ // 一个类而言,应该仅有一个引起它变化的原因
3
+ // SRP 原则体现为:一个对象(方法)只做一件事情
4
+
5
+ // SRP 原则在很多设计模式中都有着广泛的运用,例如代理模式、迭代器模式、单例模式和装 饰者模式。
6
+
7
+ //代理模式
8
+ // myImage 负责往页面中添加 img 标签:
9
+ var myImage = ( function ( ) { } {
10
+ var imgNode = document . createElement ( 'img' ) ;
11
+ document . body . appendChild ( imgNode )
12
+ return {
13
+ setSrc :function ( src ) {
14
+ imgNode . src = src ;
15
+ }
16
+ }
17
+ } ) ( )
18
+
19
+ // proxyImage 负责预加载图片,并在预加载完成之后把请求交给本体 myImage
20
+ var proxyImage = ( function ( ) {
21
+ var img = new Image ( ) ;
22
+ img . onload = function ( ) {
23
+ myImage . setSrc ( this . src )
24
+ } ;
25
+ return {
26
+ setSrc :function ( src ) {
27
+ myImage . setSrc ( 'xxx-loading.png' ) ;
28
+ img . src = src ;
29
+ }
30
+ }
31
+ } ) ( )
32
+
33
+ proxyImage . setSrc ( 'http://wwww.baidu/pic/cat.png' ) ;
34
+
35
+ //迭代器模式
36
+ var appendDiv = function ( data ) {
37
+ for ( var i = 0 , l = data . length ; i < l ; i ++ ) {
38
+ var div = document . createElement ( 'div' ) ;
39
+ div . innerHTML = data [ i ] ;
40
+ document . body . appendChild ( div )
41
+ }
42
+ }
43
+
44
+ appendDiv ( [ 1 , 2 , 3 , 4 , 5 , 6 ] ) ;
45
+
46
+ // appendDiv 函数本来只是负责渲染数据,但是在这里它还承担了遍历聚合对象 data 的职责
47
+
48
+ // 当把迭代聚合对象的职责单独封装在 each 函数中后
49
+ var each = function ( obj , callback ) {
50
+ var value , i = 0 , length = obj . length , isArray = isArrayLike ( obj ) ;
51
+
52
+ if ( isArray ) {
53
+ for ( ; i < length ; i ++ ) {
54
+ callback . call ( obj [ i ] , i , obj [ i ] ) ;
55
+ }
56
+ } else {
57
+ for ( i in obj ) {
58
+ value = callback . call ( obj [ i ] , i , obj [ i ] ) ;
59
+ }
60
+ }
61
+
62
+ return obj ;
63
+ }
64
+
65
+ var appendDiv = function ( data ) {
66
+ each ( data , function ( i , n ) {
67
+ var div = document . createElement ( 'div' ) ;
68
+ div . innerHTML = n ;
69
+ document . body . appendChild ( div ) ;
70
+ } )
71
+ }
72
+
73
+ appendDiv ( [ 1 , 2 , 3 , 4 , 5 , 6 ] ) ;
74
+ appendDiv ( { a :1 , b :2 , c :3 , d :4 } ) ;
75
+
76
+ //单例模式
77
+ //惰性单例
78
+ var createLoginLayer = ( function ( ) {
79
+ var div ;
80
+ return function ( ) {
81
+ if ( ! div ) {
82
+ div = document . createElement ( 'div' ) ;
83
+ div . innerHTML = '我是登录浮窗' ;
84
+ div . style . display = 'none' ;
85
+ document . body . appendChild ( div )
86
+ }
87
+ return div ;
88
+ }
89
+ } ) ( )
90
+
91
+ // 把管理单例的职责和创建登录浮窗的职责分别封装在两个方法里,这两个方法可以 独立变化而互不影响
92
+ var getSingle = function ( fn ) {
93
+ var result ;
94
+ return function ( ) {
95
+ return result || ( result = fn . apply ( this , arguments ) )
96
+ }
97
+ }
98
+
99
+ var createLoginLayer = function ( ) {
100
+ var div = document . createElement ( 'div' ) ;
101
+ div . innerHTML = '我是登录浮窗' ;
102
+ document . body . appendChild ( div )
103
+ return div ;
104
+ }
105
+
106
+ var createSingleLoginLayer = getSingle ( createLoginLayer ) ;
107
+ var loginLayer1 = createSingleLoginLayer ( ) ;
108
+ var loginLayer2 = createSingleLoginLayer ( ) ;
109
+ alert ( loginLayer1 === loginLayer2 ) ;
110
+
111
+ // 装饰者模式
112
+ // 装饰者模式可以为对象动态增加职责,从另一个角度来看, 这也是分离职责的一种方式
113
+ Function . prototype . prototype . after = function ( afterfn ) {
114
+ var __self = this ;
115
+ return function ( ) {
116
+ var ret = __self . apply ( this , arguments ) ;
117
+ afterfn . apply ( this , arguments ) ;
118
+ return ret ;
119
+ }
120
+ } ;
121
+
122
+ var showLogin = function ( ) {
123
+ console . log ( '打开登录浮层' )
124
+ }
125
+
126
+ var log = function ( ) {
127
+ console . log ( "上报标签为 xxx" ) ;
128
+ }
129
+
130
+ document . getElementById ( 'button' ) . onclick = showLogin . after ( log ) ;
131
+
132
+
133
+
134
+ // SRP 原则的应用难点就是如何去分离职责
135
+ // 一方面,如果随着需求的变化,有两个职责总是同时变化,那就不必分离他们
136
+ // 另一方面,职责的变化轴线仅当它们确定会发生变化时才具有意义
137
+ // SRP 原则的优点是降低了单个类或者对象的复杂度,按照职责把对象分解成更小的粒度,
138
+ // 这有助于代码的复用,也有利于进行单元测试
139
+ // SRP 原则也有一些缺点,最明显的是会增加编写代码的复杂度
140
+ // 我们按照职责把对象 分解成更小的粒度之后,实际上也增大了这些对象之间相互联系的难度
0 commit comments