2020-03-21
JavaScript
0

目录

S O L I D 五大设计原则
设计模式类型
UNIX和LINUX设计哲学
设计模式
工厂模式
构造函数模式
构造函数改进
原型模式
单例模式
装饰器模式
观察者模式
迭代器模式

设计模式在JavaScript中应用非常广泛,无论是在前端还是后端开发中都有广泛的应用。一些常见的设计模式包括单例模式、工厂模式、适配器模式、观察者模式等等。

本文将介绍JavaScript设计模式的一些基本概念和常见的应用场景,通过实例来演示如何使用这些设计模式解决实际问题。我们还将讨论如何在JavaScript代码中实现这些模式,以及它们的优缺点和使用注意事项。无论你是初学者还是有一定经验的开发人员,都能从中受益并提高你的代码质量和效率。

S O L I D 五大设计原则

S-单一职责原则 一个程序只做好一件事 如果功能过于复杂就拆分开,每个部分保持独立

O-开放封闭原则 对扩展开放,对修改封闭 增加需求时,扩展新代码,而非修复已有代码

L-里氏替换原则 子类能覆盖父类 父类能出现的地方子类就能出现 JS中使用较少(弱类型&继承使用较少)

I-接口隔离原则 保持接口的单一独立,避免出现’胖接口‘ JS中没有接口(typescript例外)

D-依赖反转原理 面向接口编程,依赖于抽象而不依赖于具体 使用方只关注接口而不关注具体类的实现 JS中使用较少(没有接口&弱类型)

设计模式类型

创建型

  • 工作模式
  • 单例模式
  • 原型模式

结构型

  • 适配器模式
  • 装饰器模式
  • 代理模式
  • 外观模式
  • 桥接模式
  • 组合模式
  • 享元模式

行为型 -1

  • 策略模式
  • 模板方法模式
  • 观察者模式
  • 迭代器模式
  • 职责连模式
  • 命令模式

行为型 -2

  • 备忘录模式
  • 状态模式
  • 访问者模式
  • 中介者模式
  • 解释器模式

UNIX和LINUX设计哲学

准则1:小即是美 准则2:让每个程序只做好一件事

准则3:快速建立原型(先满足用户最基础的需求,后续用户有反馈,在进行升级。而不是埋头一直写)

准则4:舍弃高效率而取可移植性 准则5:采用纯文本来存储数据(可读性取舍)

准则6:充分利用软件的杠杠效应(软件复用) 准则7:使用shell脚本来提高杠杆效应和可移植性

准则8:避免强制性的用户界面

准则9:让每个程序都称为过滤器

设计模式

工厂模式

js
function cPerson(name,sex,age){  var o = new Object();  o.name = name;  o.sex = sex;  o.age = age;  o.show = function(){  console.log(this.name,this.age,this.sex);  }  return o; }

工厂模式虽然解决了创建多个相似对象的问题,但是却没有解决对象识别问题(即怎样知道一个对象的类型) 工作模式需要封装new的创建 ,不让使用者去new

构造函数模式

js
function CPerson(name,sex,age) { // 注意这里 构造函数首字母大写  this.name = name;  this.sex = sex;  this.age = age;  this.show = function () {  console.log(this.name, this.age, this.sex);  } } var p1 = new CPerson('谦龙','男','100');  p1.show(); var p2 = new CPerson('雏田','女','14');  p2.show();

构造函数模式虽然好用,但也并非没有缺点。使用构造函数的主要问题,就是每个方法(其他引用类型同理)都要在实例上重新创建一遍

构造函数改进

js
function CPerson(name,sex,age) { //注意这里 构造函数首字母大写  this.name = name;  this.sex = sex;  this.age = age;  this.show = show } function show(){  console.log(this.name, this.age, this.sex); } var p1 = new CPerson('谦龙','男','100');  p1.show(); var p2 = new CPerson('雏田','女','14');  p2.show();

需要定义多个全局函数,仍然让人无法接受

困惑: 个人认为构造函数模式更好,构造函数模式,定义的引用类型,不会相互污染,而原型模式,所有的实例都共享prototype,定义的引用类型,会造成相互污染

原型模式

js
function CPerson(){ } CPerson.prototype.name='谦龙'; CPerson.prototype.sex='男'; CPerson.prototype.age=100; CPerson.prototype.show=function(){  console.log(this.name, this.age, this.sex); } var p1 = new CPerson();  p1.show(); //谦龙 100 男 var p2 = new CPerson();  p2.show();//谦龙 100 男  console.log(p1.show == p2.show)//true

单例模式

js
class A { static instance=null constructor (){ console.log('create') } static getInstance(){ if(this.instance instanceof A)return this.instance return this.instance=new A() } }

装饰器模式

js
// 例子1:静态方法添加 @testDec class Demo{ } function testDec(target){ target.isDec=true } // 例子2:装饰器参数 @testDec(false) class Demo{ } function testDec(isDec){ return function(target){ target.isDec=isDec } } // 例子3:实例方法添加(prototype) let Foo={ alert(){ alert(1) } } @mixins(Foo) class Demo{ } function mixins(...list){ return function(target){ Object.assign(target.prototype,...list) } } // 例子4:类的实例方法装饰 function readonly(flag){ return function(target,name,descriptor){ descriptor.writable=!flag } } class Demo{ @readonly(true) getName(){ } }
  1. 为对象添加新功能
  2. 不改变其原有结构和结构功能

观察者模式

Subject:发布者:相当于发布订阅模式的发布者(Publish)

Observer:观察者,相当于发布订阅模式的订阅者(Subscribe)

js
class Subject { constructor (){ this.state=0 this.observers=[] } getState(){ return this.state } setState(state){ this.state=state this.notify() } notify(){ this.observers.forEach(observer=>{ observer.update(this.state) }) } addObserver(observer){ this.observers.push(observer) } } class Observer{ constructor (name,subject,fn){ this.name=name this.fn=fn this.subject=subject this.subject.addObserver(this) } update(state){ console.log(this.name,'已成功被订阅') this.fn(state) } } //观察Subject const subject=new Subject() const o1=new Observer('o1',subject,function(state){ console.log('已经接收到state',state) }) const o2=new Observer('o2',subject,function(state){ console.log('已经接收到state',state) }) subject.setState(1)

迭代器模式

js
class Iterator{ constructor (list) { this.list=list this.index=0 } hasNext(){ return this.index<this.list.length } next(){ if(this.hasNext()){ return this.list[this.index++] } } } const arr=[1,2,3] const iterator=new Iterator(arr) while(iterator.hasNext()){ console.log(iterator.next()) }
js
let arr=[1,2,3,4,5,6] function each(data){ let iterator=data[Symbol.iterator]() let item={done:false} while(!item.done){ item=iterator.next() if(!item.done)console.log(item) } } each(arr)
  1. 也可以直接使用for of 去进行遍历
  2. 需要具有迭代器方法的才能进行遍历,如:Array.prototype[Symbol.iterator] ,Map.prototype[Symbol.iterator]等存在
  3. Object.prototype[Symbol.iterator]不存在迭代器,所以无法使用for of进行遍历

本文作者:BARM

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!