Skip to content

Commit 051d5f7

Browse files
committed
模版模式
1 parent 49e1af7 commit 051d5f7

File tree

1 file changed

+237
-0
lines changed

1 file changed

+237
-0
lines changed

eleven-chapter/template.js

+237
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
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

Comments
 (0)