十道前端面试题第【05】篇
2021-05-18 本文已影响0人
夏海峰
摘要:本篇是设计模式专题,分享了10个设计模式的JS示例代码——工厂模式、单例模式、原型模式、建造者模式、外观模式、享元模式、组合模式、适配器模式、中介者模式、观察者模式。
学习资源推荐: JS设计模式文集、图说设计模式、一句话归纳设计模式

1、工厂模式(Factory Pattern)
// 篮球基类
var Basketball = function(){
this.info = '篮球流行于美国';
};
Basketball.prototype = {
getMeber : function(){
console.log('每个队有5名球员');
},
getBallSize: function(){
console.log('5号球');
}
};
// 足球基类
var Football = function(){
this.info = '足球流行于巴西';
};
Football.prototype = {
getMeber: function(){
console.log('每队有11名球员');
},
getBallSize: function(){
console.log('7号球');
}
};
// 网球基类
var Tennis = function(){
this.info = '网球流行于法国';
};
Tennis.prototype = {
getMeber: function(){
console.log('每队只有1名球员');
},
getBallSize: function(){
console.log('11号球');
}
};
// 简单工厂模式:‘运动工厂’,它会帮你找到篮球、足球和网球等
var SportFactory = function(name){
switch(name){
case 'NBA':
return new Basketball();
case 'worldCup':
return new Football();
case 'FrenchOpen':
return new Tennis();
};
};
// 测试
var football = SportFactory('worldCup');
console.log(football);
console.log(football.info);
console.log(football.getBallSize());
2、单例模式(Singleton Pattern)
// 单例的延迟创建、惰性创建
var LazySingle = (function(){
// 单例实例的引用
var _instance = null;
// 单例
function Single(){
return {
publicMethod: function(){},
publicProperty: '1.0'
}
}
// 延迟创建单例
return function(){
if(!_instance){
_instance = Single();
}
return _instance;
}
})();
// 测试
console.log(LazySingle().publicProperty);
3、原型模式(Prototype Pattern)
// 基类
var LoopImages = function(imgArr,container){
this.imagesArray = imgArr;
this.container = container;
}
// 把基类中的方法提取出来,放到原型链中去
LoopImages.prototype = {
createImage: function(){
console.log('LoopImages');
},
changeImage: function(){
console.log('切换');
}
}
// 封装上下滑动的轮播类,并覆写changeImage()方法
var SlideLoopImg = function(imgArr,container){
LoopImages.call(this,imgArr,container);
}
SlideLoopImg.prototype = new LoopImages();
SlideLoopImg.prototype.changeImage = function(){
console.log('上下切换');
}
// 封装渐隐切换的轮播类,并覆写changeImage()方法
var FadeLoopImg = function(imgArr,container,arrow){
LoopImages.call(this,imgArr,container);
}
FadeLoopImg.prototype = new LoopImages();
FadeLoopImg.prototype.changeImage = function(){
console.log('渐隐切换');
}
// 对轮播基类的扩展,子类可以共享到这些扩展
LoopImages.prototype.getImageLength = function(){
return this.imagesArray.length;
}
// 扩展渐隐轮播类。对子类扩展,不影响同级的子类
FadeLoopImg.prototype.getContainer = function(){
return this.container;
}
4、建造者模式(Builder Pattern)
// 人的相关描述
var Human = function(param){
this.skill = param && param.skill || '保密';
this.hobby = param && param.hobby || '保密';
}
Human.prototype = {
getSkill: function(){
return this.skill;
},
getHobby: function(){
return this.hobby;
}
}
// 人的姓名
var Named = function(name){
var that = this;
(function(name,that){
that.wholeName = name;
if(name.indexOf(' ') > -1){
that.FirstName = name.slice(0,name.indexOf(' '));
that.SecondName = name.slice(name.indexOf(' '));
}
})(name,that);
}
// 人的职业及职业描述
var Work = function(work){
var that = this;
(function(work,that){
switch(work){
case 'code':
that.work = '工程师';
that.workDescript = '每天沉醉于编程';
break;
case 'UI':
case 'UE':
that.work = '设计师';
that.workDescript = '设计更像一种艺术';
break;
case 'teach':
that.work = '老师';
that.workDescript = '分享也是一种快乐';
break;
}
})(work,that);
}
Work.prototype.changeWork = function(work){
this.work = work;
}
Work.prototype.changeDescript = function(setence){
this.workDescript = setence;
}
// 建造者模式:用3个类组合调用,创建出一个完整的Person类
// Person类由 Human / Named / Work 三个类组合而成
var Person = function(name,work){
var _person = new Human();
// 关注对象创建的细节和过程
_person.name = new Named(name);
_person.work = new Work(work);
return _person;
}
// 测试
var person = new Person('xiao ming', 'code');
console.log(person.skill);
console.log(person.name.FirstName);
console.log(person.work.work);
console.log(person.work.workDescript);
person.work.changeDescript('更改一下职位描述');
console.log(person.work.workDescript);
5、外观模式(Facade Pattern)
// 外观模式
function addEvent(dom,type,fn){
if(dom.addEventListener){
dom.addEventListener(type,fn,false);
}else if(dom.attachEvent){
dom.attachEvent('on'+type,fn);
}else{
dom['on'+type] = fn;
}
}
// 测试
addEvent(document, 'click', function(){
console.log('11');
});
addEvent(document, 'click', function(){
console.log('22');
});
6、享元模式(Flyweight Pattern)
var FlyWeight = {
moveX: function(x) {
this.x = x;
},
moveY: function(y) {
this.y = y;
}
}
var Player = function(x, y, color) {
this.x = x;
this.y = y;
this.color = color;
}
Player.prototype = FlyWeight;
Player.prototype.changeColor = function(color) {
this.color = color;
}
// 让精灵继承移动的方法
var Spirit = function(x, y, r) {
this.x = x;
this.y = y;
this.r = r;
}
Spirit.prototype = FlyWeight;
Spirit.prototype.changeR = function(r) {
this.r = r;
}
7、组合模式(Composite Pattern)
var oForm = new FormItem('form-item', document.body);
oForm.add(
new FieldsetItem('account', '账号').add(
new Group().add(
new LabelItem('user-name', '用户名:')
).add(
new InputItem('user-name')
).add(
new SpanItem('4到6位数字或字母')
)
).add(
new Group().add(
new LabelItem('user-password', '密码:')
).add(
new InputItem('user-password')
).add(
new SpanItem('6位12位数字或者密码')
)
)
).add(
// ...
).show();
8、适配器模式(Adapter Pattern)
// 库B的源码如下:
var B = B || {};
B.g = function(id){
return document.getElementById(id);
};
B.on = function(id,type,fn){
var dom = typeof if === 'string' ? this.g(id) : id;
if(dom.addEventListener){
dom.addEventListener(type,fn,false);
}else if(dom.attachEvent){
dom.attachEvent('on'+type,fn);
}else{
dom['on'+type] = fn;
}
}
// 适配器模式,把B框架转换成jQuery,并覆写B库的两个方法
window.B = B = jQuery;
B.g = function(id){
return $(id).get(0);
}
B.on = function(id,type,fn){
var dom = typeof id === 'string' ? $('#'+id) : $(id);
dom.on(type,fn);
}
9、中介者模式(Mediator Pattern)
// 中介者模式
var Mediator = function() {
// 消息对象
var _msg = {};
return {
// 注册:向指定类型中追加新的功能方法
register: function(type, action) {
if (_msg[type]) {
_msg[type].push(action);
} else {
_msg[type] = [];
_msg[type].push(action);
}
},
// 发布:调用指定类型中的功能方法集
send: function(type) {
if (_msg[type]) {
for (var i=0; i<_msg[type].length; i++) {
_msg[type][i] && _msg[type][i]();
}
}
}
}
}();
10、观察者模式(Observer Pattern)
// 把观察者放在闭包中,当页面加载时就立即执行
var Observer = (function() {
// 防止消息队列暴露而被篡改,因此我们要把消息容器作为静态私有变量
var _messages = {};
return {
// 注册订阅
regist: function(type, fn) {
if (typeof _messages[type] === 'undefined') {
// 如果此消息不存在,则创建一个新的消息类型,并把消息放入到队列中去
_messages[type] = [fn];
} else {
// 如果此消息存在,直接把消息追加到队列中去
_messages[type].push(fn);
}
},
// 消息发布
fire: function(type, args) {
if(!_messages[type]) return;
// 定义消息信息
var events = {
type: type,
args: args || {}
};
for (var i=0; i<_messages[type].length; i++) {
// 依次执行注册的消息对应的动作序列
_messages[type][i].call(this, events);
}
},
// 取消订阅
remove: function(type) {
if (_messages[type] instanceof Array) {
for (var i=_messages[type].length-1; i>=0; i--) {
// 如果存在该动作则从消息动作序列中移除相应动作
_messages[type].splice(i, 1);
}
}
}
}
})();
// 订阅一条消息
Observer.regist('test', function(e) {
console.log(e.type, e.args.msg);
});
// 发布消息
Observer.fire('test', {msg: '传递参数'});
本周结束,下周继续!!!