前言
生活中我们时刻能感受到套路的好处,比如用土味情话追妹子,虽然可能会显得你很老土,但是也不至于冷场,起码还显得你幽默。在写代码的过程中同样可以使用一些套路,使你的代码看起来是高雅的、有艺术气息的。设计模式就是这样一种套路,提高你写代码的效率,重用性、让代码更容易被他人理解、保证代码可靠性等等,不仅显得你气质非凡,还显得你666!!!
设计模式的'道德规范'---原则
设计模式的原则就如同我们生活中的道德规范,你可以不去遵循,那在外人看来你就是***。同样你使用设计模式不去遵循设计模式的原则,你的代码也就是那啥。
- 单一原则 一次只能做一件事情,单一原则可以减低程序的复杂性,但会随即增加耦合度。上厕所不能同时吃饭,这是一件很恶心的事(这样的代码也着实很恶心),虽然你想秉着节约时间的原则,但你要权衡利弊啊,不要做这么恶心的事。
- 里氏替换原则 子类可以替换父类,父类不能替换子类。你喜欢所有的妹子,可以推断出你喜欢你女朋友(因为女朋友是妹子的子集),你喜欢你的女朋友,不能推断出你喜欢所有的妹子(搓衣板跪穿的事!!!)
- 开闭原则 关闭修改,开启扩展。小时候,你父亲要求你什么都得会【开启扩展】,但是你不能要求你父亲什么都会(毕竟你知道你不是对手)【关闭修改】。
- 最小知道原则 要降低耦合度,降低风险。藏私房钱,只能天知地知我知,才能最大限度保证私房钱的安全。
- 依赖倒置原则 同样降低耦合度,比如vuex。你看中了一个妹子,不好意思直接要联系方式,你差你的好兄弟,去找人要联系方式,他拿到联系方式再给你。
- 接口分离原则 与单一原则类似,每个接口做一件事。追班花要一个一个的追,追班花时还打望隔壁的班花,班花走了,还得被隔壁班男生追,这不愁人嘛。
- 权衡 (可忽略) 不是所有代码都得用设计模式,不是所有设计模式都得遵循所有原则。杀鸡焉用宰牛刀,权衡其利弊才是智者。
设计模式
- 单例模式
保证一个类只有一个实例,无论执行多少次new操作都生成一个相同的实例
圣杯写法(yahoo提出用圣杯模式去封装一个继承方法)
const siglePattern = (()=>{
let _onlyObj = null; // 利用闭包,保存唯一的对象
return function (){
if(_onlyObj === null){
this.name = name;
_onlyObj = this;
}
return _onlyObj;
}
})()
// 封装上面的方法 func为一个正常的构造函数
const singleHandle = function (func){
let result = null;
return function () {
if(result !== null){
result = func.apply(this,arguments)
}
return result;
}
}
- 代理模式
实现一个场景:放学给隔壁班花给她送开水,此时你需要一个代理来保证班花放学一定有开水,不然班花就有可能喝不到你的开水。
const classFlower = {
name: '阿花',
isClassOver: false,
leaveSchool() {
setInterval(() => {
if (Math.random() > 0.5) {
this.isClassOver = true
}
}, 200);
},
reply() {
console.log(`你好!我是${this.name},谢谢你的开水`)
}
}
classFlower.leaveSchool() // 仅仅为了开启是否放学了
const Diaos = {
name: '阿雕',
sendWater(obj) {
console.log(`你好,我是${this.name},多喝点开水`)
if (obj.isClassOver) {
obj.reply();
} else {
console.log('班花可能走了,可能还没有下课')
}
}
}
// 因为事件循环原因,所以将其放置延时器中。
// Diaos同学只能凭借运气好坏,给班花打招呼
// 此时Diaos同学就需要找一个代理人,告诉他什么时候该去,才不让自己扑空
setTimeout(() => {
Diaos.sendWater(classFlower)
}, 300);
const Dproxy = {
name: '职业班花代理人',
listener(origin, target) {
this.tiemr = setInterval(() => {
if (target.isClassOver) {
clearInterval(this.tiemr)
origin.sendWater(target)
}
}, 300);
}
}
Dproxy.listener(Diaos,classFlower) //找班花闺蜜,班花要走的时候通知自己执行打招呼,这样可以告别等待,百发百中。
- 策略模式
实现表单验证,当点击提交时开始验证
结构代码
<label for="username">
username: <input type="text" id="username">
</label>
<span class="msg"></span>
<br>
<label for="email">
email: <input type="text" id="email">
</label>
<span class="msg"></span>
<br>
<!-- 点击提交按钮开始验证 -->
<button id="btn">submit</button>
js部分代码
// 构建一个管理验证表单的对象,可通过add方法添加验证方式,run方法执行,extend扩展验证方法
class Validator {
constructor () {
// 缓存验证方式
this.cache = [];
// 缓存显示信息的位置,满足条件后清除
this.showDom = [];
}
// 为需要验证的表单值添加验证方式,传值为需要验证的dom,需要把错误显示到的地方,需要用到那些方法(数组)
add(dom,showDom,methods){
// 缓存显示位置
this.showDom.push(showDom)
// 遍历所需方式
methods.forEach((ele,index)=>{
// 这些方法以及参数保存在实例中,开闭原则
this.cache.push(()=>{
// 处理参数
const parameter = ele.method.split(':')
const method = parameter.shift();
parameter.unshift(dom.value);
parameter.push(ele.msg);
// 执行验证方法并保存结果
const result = this.methodStore[method](...parameter);
// 判断是否有错误消息,并显示在对应的位置
if(result != true){
showDom.innerText = result;
}
return result
})
})
}
// 执行实例中缓存的方法
run(){
// 清除上一次显示的错误信息
this.showDom.forEach(ele => {
ele.innerText = ''
})
// 最后返回给调用此策略的用户是否通过指定的验证方式
let flag = true;
// 执行缓存中的方法
this.cache.forEach((ele,index)=>{
if(ele() != true){
flag = false;
}
})
// 防止多次验证无限缓存相同方法
// 可以使用代理模式进行优化
this.cache.length = 0;
return flag;
}
// 扩展验证方式
extend(config){
for (const key in config) {
this.methodStore[key] = config[key]
}
}
}
// 验证方式仓库,可通过extend方法进行添加
Validator.prototype.methodStore = {
isEmpty(value,msg){
if(value === ''){
return msg;
}
return true;
},
minLength(value,len,msg){
if(value != '' && value.length < len){
return msg
}
return true;
}
}
// 使用Validator对象,这里可以使用代理模式配合使用
const validator = new Validator();
// 使用扩展方式添加验证邮箱
validator.extend({
isEmail(value,msg){
const reg = /^([0-9A-z-_])+@([0-9A-z-_])+(\.[0-9A-z-_]+)/
if(value != '' && !reg.test(value)){
return msg;
}
return true;
}
});
const oUserName = document.getElementById('username');
const oMsg = document.getElementsByClassName('msg');
const oEmail = document.getElementById('email');
const oBtn = document.getElementById('btn')
oBtn.onclick = function () {
validator.add(oUserName,oMsg[0],[{method:'isEmpty',msg:'Empty!!!!'},{method:'minLength:3',msg:'length!!!'}])
validator.add(oEmail,oMsg[1],[{method:'isEmpty',msg:'Empty!!!!'},{method:'isEmail',msg:'not is email!!!'}])
validator.run();
}
总结
设计模式是前辈为我们泡代码提供的一些套路,套路千万条,合适第一条,一定要权衡利弊。滥用设计模式,可能适得其反也就体验不到设计模式的威力。
** 建议看完相应的代码再查阅各个设计模式的定义,以便更好的掌握,区分。