设计模式在JavaScript中应用非常广泛,无论是在前端还是后端开发中都有广泛的应用。一些常见的设计模式包括单例模式、工厂模式、适配器模式、观察者模式等等。
本文将介绍JavaScript设计模式的一些基本概念和常见的应用场景,通过实例来演示如何使用这些设计模式解决实际问题。我们还将讨论如何在JavaScript代码中实现这些模式,以及它们的优缺点和使用注意事项。无论你是初学者还是有一定经验的开发人员,都能从中受益并提高你的代码质量和效率。
S-单一职责原则 一个程序只做好一件事 如果功能过于复杂就拆分开,每个部分保持独立
O-开放封闭原则 对扩展开放,对修改封闭 增加需求时,扩展新代码,而非修复已有代码
L-里氏替换原则 子类能覆盖父类 父类能出现的地方子类就能出现 JS中使用较少(弱类型&继承使用较少)
I-接口隔离原则 保持接口的单一独立,避免出现’胖接口‘ JS中没有接口(typescript例外)
D-依赖反转原理 面向接口编程,依赖于抽象而不依赖于具体 使用方只关注接口而不关注具体类的实现 JS中使用较少(没有接口&弱类型)
创建型
结构型
行为型 -1
行为型 -2
准则1:小即是美 准则2:让每个程序只做好一件事
准则3:快速建立原型(先满足用户最基础的需求,后续用户有反馈,在进行升级。而不是埋头一直写)
准则4:舍弃高效率而取可移植性 准则5:采用纯文本来存储数据(可读性取舍)
准则6:充分利用软件的杠杠效应(软件复用) 准则7:使用shell脚本来提高杠杆效应和可移植性
准则8:避免强制性的用户界面
准则9:让每个程序都称为过滤器
jsfunction 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
jsfunction 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();
构造函数模式虽然好用,但也并非没有缺点。使用构造函数的主要问题,就是每个方法(其他引用类型同理)都要在实例上重新创建一遍
jsfunction 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,定义的引用类型,会造成相互污染
jsfunction 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
jsclass 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(){
}
}
Subject:发布者:相当于发布订阅模式的发布者(Publish)
Observer:观察者,相当于发布订阅模式的订阅者(Subscribe)
jsclass 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)
jsclass 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())
}
jslet 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)
本文作者:BARM
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!