1
+ // 模板方法模式是一种只需使用继承就可以实现的非常简单的模式
2
+ // 模板方法模式由两部分结构组成,第一部分是抽象父类,第二部分是具体的实现子类
3
+
4
+ //coffer or tea
5
+
6
+ var Coffee = function ( ) {
7
+
8
+ }
9
+
10
+ Coffee . prototype . boilWater = function ( ) {
11
+ console . log ( 'boilWater' )
12
+ }
13
+ Coffee . prototype . brewCoffeeGriends = function ( ) {
14
+ console . log ( 'brewCoffeeGriends' )
15
+ }
16
+
17
+ Coffee . prototype . pourInCup = function ( ) {
18
+ console . log ( 'pourInCup' )
19
+ }
20
+
21
+ Coffee . prototype . addSugarAndMilk = function ( ) {
22
+ console . log ( 'addSugarAndMilk' )
23
+ }
24
+
25
+ Coffee . prototype . init = function ( ) {
26
+ this . boilWater ( ) ;
27
+ this . brewCoffeeGriends ( ) ;
28
+ this . pourInCup ( ) ;
29
+ this . addSugarAndMilk ( ) ;
30
+ }
31
+
32
+ var coffee = new Coffee ( ) ;
33
+ coffee . init ( ) ;
34
+
35
+ //泡一壶茶
36
+ var Tea = function ( ) {
37
+
38
+ }
39
+
40
+ Tea . prototype . boilWater = function ( ) {
41
+ console . log ( 'boilWater' )
42
+ }
43
+ Tea . prototype . steepTeaBag = function ( ) {
44
+ console . log ( 'steepTeaBag' )
45
+ }
46
+
47
+ Tea . prototype . pourInCup = function ( ) {
48
+ console . log ( 'pourInCup' )
49
+ }
50
+
51
+ Tea . prototype . addLemon = function ( ) {
52
+ console . log ( 'addLemon' )
53
+ }
54
+
55
+ Tea . prototype . init = function ( ) {
56
+ this . boilWater ( ) ;
57
+ this . steepTeaBag ( ) ;
58
+ this . pourInCup ( ) ;
59
+ this . addLemon ( ) ;
60
+ }
61
+
62
+ var tea = new Tea ( ) ;
63
+ tea . init ( ) ;
64
+
65
+ /*
66
+ (1) 把水煮沸
67
+ (2) 用沸水冲泡饮料
68
+ (3) 把饮料倒进杯子
69
+ (4) 加调料
70
+ */
71
+
72
+ var Beverage = function ( ) { }
73
+
74
+ Beverage . prototype . boilWater = function ( ) {
75
+ console . log ( 'boilWater' )
76
+ }
77
+ Beverage . prototype . brew = function ( ) {
78
+ throw new Error ( '子类必须重写 brew 方法' )
79
+ } ;
80
+ Beverage . prototype . pourInCup = function ( ) {
81
+ throw new Error ( '子类必须重写 pourInCup 方法' )
82
+ } ;
83
+ Beverage . prototype . addCondiment = function ( ) {
84
+ throw new Error ( '子类必须重写 addCondiment 方法' )
85
+ } ;
86
+
87
+ Beverage . prototype . customerWantsCondiment = function ( ) {
88
+ return true ; //默认需要调料
89
+ }
90
+
91
+ // Beverage.prototype.init 被称为模板方法的原因是,
92
+ // 该方法中封装了子类的算法框架,它作 为一个算法的模板,
93
+ // 指导子类以何种顺序去执行哪些方法
94
+ Beverage . prototype . init = function ( ) {
95
+ this . boilWater ( )
96
+ this . brew ( )
97
+ this . pourInCup ( )
98
+ if ( this . customerWantsCondiment ( ) ) { // 如果挂钩返回 true,则需要调料
99
+ this . addCondiment ( )
100
+ }
101
+
102
+ } ;
103
+
104
+ var Coffee = function ( ) { }
105
+ Coffee . prototype = new Beverage ( ) ;
106
+
107
+ Coffee . prototype . brew = function ( ) {
108
+ console . log ( '用沸水冲泡咖啡' )
109
+ }
110
+ Coffee . prototype . pourInCup = function ( ) {
111
+ console . log ( '把咖啡倒景杯子里' )
112
+ }
113
+ Coffee . prototype . addCondiment = function ( ) {
114
+ console . log ( '加糖和牛奶' )
115
+ }
116
+
117
+ var Coffee = new Coffee ( )
118
+ Coffee . init ( )
119
+
120
+ var Tea = function ( ) { }
121
+ Tea . prototype = new Beverage ( ) ;
122
+
123
+ Tea . prototype . brew = function ( ) {
124
+ console . log ( '用沸水浸泡茶叶' )
125
+ }
126
+
127
+ Tea . prototype . pourInCup = function ( ) {
128
+ console . log ( '把茶叶倒进杯子' )
129
+ }
130
+ Tea . prototype . addCondiment = function ( ) {
131
+ console . log ( '加柠檬' )
132
+ }
133
+
134
+ var tea = new Tea ( )
135
+ tea . init ( )
136
+
137
+ //模版模式的使用场景
138
+ /**
139
+ 模板方法模式常被架构师用于搭建项目的框架,架构师定好了框架的骨架,
140
+ 程序员继承框架的结构之后,负责往里面填空
141
+ **/
142
+
143
+ // 在 Web 开发中也能找到很多模板方法模式的适用场景
144
+ // ,比如我们在构建一系列的 UI 组件, 这些组件的构建过程一般如下所示:
145
+
146
+ /*
147
+ (1) 初始化一个 div 容器;
148
+ (2) 通过 ajax 请求拉取相应的数据; 不一样
149
+ (3) 把数据渲染到 div 容器里面,完成组件的构造; 不一样
150
+ (4) 通知用户组件渲染完毕。
151
+ */
152
+
153
+ //钩子方法(hook)可以用来解决这个问题,放置钩子是隔离变化的一种常见手段
154
+ var CoffeeWithHook = function ( ) { }
155
+ CoffeeWithHook . prototype = new Beverage ( ) ;
156
+ CoffeeWithHook . prototype . brew = function ( ) {
157
+ console . log ( '用沸水冲泡咖啡' )
158
+ } ;
159
+ CoffeeWithHook . prototype . pourInCup = function ( argument ) {
160
+ console . log ( '把咖啡倒进杯子' )
161
+ } ;
162
+ CoffeeWithHook . prototype . addCondiment = function ( argument ) {
163
+ console . log ( '加糖和牛奶' )
164
+ } ;
165
+ CoffeeWithHook . prototype . customerWantsCondiment = function ( argument ) {
166
+ return window . confirm ( '请问需要调料吗?' )
167
+ } ;
168
+
169
+ var coffeeWithHook = new CoffeeWithHook ( )
170
+ CoffeeWithHook . init ( ) ;
171
+
172
+ //好莱坞原则
173
+ // 底层组件将自己 挂钩到高层组件中,而高层组件会决定什么时候、以何种方式去使用这些底层组件
174
+ // 发布订阅模式 回调函数
175
+
176
+ //但在 JavaScript 中,我们很多时候都不需要依样画瓢地去实现一个模版方法模式,高阶函数 是更好的选择。
177
+
178
+ // 在好莱坞原则的指导之下,下面这段代码可以达到和继承一样的效果
179
+ var Beverage = function ( param ) {
180
+ var boilWater = function ( ) {
181
+ console . log ( '把水煮沸' )
182
+ } ;
183
+
184
+ var brew = param . brew || function ( ) {
185
+ throw new Error ( '必须传递brew方法' )
186
+ } ;
187
+
188
+ var pourInCup = param . pourInCup || function ( ) {
189
+ throw new Error ( '必须传递pourInCup方法' )
190
+ } ;
191
+
192
+ var addCondiments = param . addCondiments || function ( ) {
193
+ throw new Error ( '必须传递addCondiments方法' )
194
+ } ;
195
+
196
+ var F = function ( ) { } //构造器
197
+
198
+ F . prototype . init = function ( ) {
199
+ boilWater ( ) ;
200
+ brew ( ) ;
201
+ pourInCup ( ) ;
202
+ addCondiment ( ) ;
203
+ }
204
+
205
+ return F ;
206
+
207
+ }
208
+
209
+ var Coffee = Beverage ( {
210
+ brew : function ( ) {
211
+ console . log ( '用沸水冲泡咖啡' ) ;
212
+ } ,
213
+ pourInCup : function ( ) {
214
+ console . log ( '把咖啡倒进杯子' ) ;
215
+ } ,
216
+ addCondiments : function ( ) {
217
+ console . log ( '加糖和牛奶' ) ;
218
+ }
219
+ } ) ;
220
+
221
+ var Tea = Beverage ( {
222
+ brew : function ( ) {
223
+ console . log ( '用沸水浸泡茶叶' ) ;
224
+ } ,
225
+ pourInCup : function ( ) {
226
+ console . log ( '把茶倒进杯子' ) ;
227
+ } ,
228
+ addCondiments : function ( ) {
229
+ console . log ( '加柠檬' ) ;
230
+ }
231
+ } ) ;
232
+
233
+ var coffee = new Coffee ( ) ;
234
+ coffee . init ( )
235
+
236
+ var tea = new Tea ( )
237
+ tea . init ( )
0 commit comments