JavaScript 设计模式

860 阅读5分钟

一种设计模式应该包括下列元素

模式名称 描述 上下文大纲 问题陈述 解决方案 设计 实现 插图 示例 辅助条件 关系 已知的用法 讨论

直接给出解释与案例分析,帮助理解

构造器模式

构造器是一种内存已分配给该对象的情况下,用于初始化新对象的的特殊方法
  1. 基本构造器 Constructor

    function Person(name,age,sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.personalString = function(){
            return '姓名:'+ this.name + ' 年龄:' + this.age + ' 性别:' + this.sex   
        }
    }
    <!--example-->
    var xiaoming = new Person('小明','18','男');
    console.log(xiaoming.personalString())
    <!----姓名:小明 年龄:18 性别:男>
    

    缺点: 基本构造器 继承变得很困难

  2. 带原型的构造器 Constructor

    function Person(name,age,sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    Person.prototype.personalString = function(){
        return '姓名:'+ this.name + ' 年龄:' + this.age + ' 性别:' + this.sex   
    }
    <!--example-->
    var xiaoming = new Person('小玲','17','女');
    console.log(xiaoming.personalString())
    <!----姓名:小玲 年龄:17 性别:女>
    

理解: 构造器模式利用new关键字 创建不同的示例,示例的__proto__.contructor指向同一个构造函数 xiaoming.__proto__.constructor === Person



模块模式

Module 最初为一种传统软件工程中为类提供私有和公有方法封装的方
var countModule = (function(){
    var counter = 0;
    return {
        add:function(){
            return ++counter;
        },
        min:function(){
            return --counter;
        }
    }
})();
<!--example-->
countModule.add() //--> 1
countModule.add() //--> 2
countModule.min() //--> 1
var myModule = (function(){
    var module = {},
        privateVariable = "hello world";
    function privateMethod(){
        
    }
    module.publicProperty = "Foobar";
    module.publicMethod = function(){
        console.log(privateVariable);
    };
    return module;
})

声明对象,挂载注册,直接return输出,重新赋值挂载到声明的全局变量

理解: 利用闭包达到维系私有变量,防止污染全局作用域,隔离与其他开发者 引用冲突



代理模式

为一个对象提供一个代用品或占位符,以便控制对它的访问。例如图片懒加载业务模型
var imgFunc = (function() {
    var imgNode = document.createElement('img');
    document.body.appendChild(imgNode);
    return {
        setSrc: function(src) {
            imgNode.src = src;
        }
    }
})();
var proxyImage = (function() {
    var img = new Image();
    img.onload = function() {
        imgFunc.setSrc(this.src);
    }
    return {
        setSrc: function(src) {
            imgFunc.setSrc('./loading,gif');
            img.src = src;
        }
    }
})();
proxyImage.setSrc('./pic.png');


单例模式

单例模式的定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。实现的方法为先判断实例存在与否,如果存在则直接返回,如果不存在就创建了再返回,这就确保了一个类只有一个实例对象。
class CreatePerson {
    constructor(name) {
        this.name = name;
        this.getName();
    }
    getName() {
         return this.name;
    }
}
// 代理实现单例模式
var Person = (function() {
    var instance = null;
    return function(name) {
        if(!instance) {
            instance = new CreatePerson(name);
        }
        return instance;
    }
})();

// test
var a = new Person("aaa");
var b = new Person("bbb");

console.log(a === b);    
//true


观察者模式

对目标状态感兴趣的一个或多个观察者,通过将自身与该目标关联在一起的形式进行注册。当目标出现观察者可能感兴趣的变化时,发出提醒消息,进而调用每个观察者的更新方法。如果观察者对目标状态不再感兴趣,只需要解除关联即可。
1. Subject 目标
维护一系列的观察者,方便添加或删除观察者
2. Observer 观察者
为那些在目标状态发生改变时,需要获得通知的对象提供一个更新接口
3. ConcreteSubject 具体目标
状态发生改时,向 Observer 发出通知,存储 ConcreteSubject 状态
4.ConcreteObserver 具体观察者
存储一个指向ConcreteSubject的饮用,实现Observer的更新接口,以️使自身状态与目标的状态保持一致
function Tweeter () {
    var subject = new Subject();
    this.addObserver = function (observer) {
        subject.add_observer(observer);
    };
    this.removeObserver = function (observer) {
        subject.remove_observer(observer);
    };
    this.fetchTweets = function fetchTweets () {
        // tweet
        var tweet = {
            tweet: "This is one nice Observer"
        };
        // 提示观察者发生的变化
        subject.notify(tweet);
    };
}

// 添加观察者

var TweetUpdater = {
    update: function () {
        console.log('Update Tweet - ', arguments);
    }
};

var TweetFollower = {
    update: function () {
        console.log('Following this tweet - ', arguments);
    }
};


var tweetApp = new Tweeter();
tweetApp.addObserver(TweeterUpdater);
tweetApp.addObserver(TweeterFollower);
tweetApp.fetchTweets();
tweetApp.removeObserver(TweetUpdater);
tweetApp.removeObserver(TweetFollower);



Mixin模式

如果有可以在多个对象和类层次之间共享的功能,可以使用 mixin;如果要共享的功能是在单个层次中,可以使用继承。在原型继承中,如果继承来自原型,那么对原型做出的修改会影响到从原型继承的一切内容。如果不希望出现这种情况,可以使用 mixin
var _ = require('underscore');
// 将共享的功能封装进 CustomLogger
var logger = (function () {
    var CustomLogger = {
        log: function (message) {
            console.log(message);
        }
    };
    return CustomLogger
}())

// 需要定制的日志记录器来记录系统特定日志的对象
var Server = (function (Logger) {
    var CustomServer = function () {
        this.init = function () {
            this.log("Initializing Server...");
        };
    };
    
    // 将 CustomLogger 的成员复制/扩展为 CustomServer
    _.extend(CustomServer.prototype, Logger);
    return CustomServer;
}(logger));

(new Server()).init();


原型模式

用原型实例指向创建对象的种类,并且通过拷贝这些原型创建新的对象
function Person () {
  this.name = 'ivan'
  this.sex = '28'
  this.age = '男'
  this.getName=function () {
    return `姓名:${this.name}`
  }
}
Person.prototype.getInfo = function () {
  return `姓名: ${this.name}, 年龄: ${this.age}, 性别:${this.sex}`
}

let person = new Person()

const person1 = Object.create(proto)
const person2 = Object.create(proto)

person1.name //"ivan"
person2.name //"ivan"

person1.name = 'xxx' // "xxx"
person2.name   //"ivan"


命令模式

将方法调用 请求 操作封装到单一对象中,从而根据我们不同的请求对客户进行参数化与传递可供执行的方法调用。此外,这种模式将调用操作的对象与知道如何实现该操作的对象解偶,并在交换出具体类方面提供更大的整体灵活性。
* 通过假设桥梁,降低耦合,一定程度遵从OOP
let CarManager = (() => {
  return {
    requesrInfo: (model, id) =>{
      return 'The information for ' + model + 'width ID' + id + 'is foobar'
    },
    buyVehicle: (model, id) =>{
      return 'purchased Item ' + model + ', ' + id
    },
    arrangeView: (model, id) =>{
      return 'You have successfully booked a viewing of ' + model + ' ' + id
    },
    execute: (...arg) => {
      return CarManager[arg[0]] && CarManager[arg[0]].apply(CarManager,[].slice.call(arg,1))
    }
  }
})()

CarManager.execute('arrangeView','ff','123')


外观模式

为更大的代码体提供一个方便的高层次接口,能够隐藏其底层的真是复杂度,可以理解成库的API
let module = (() => {
  let _private = {
    i: 5,
    get: () => {
      console.log(this.i)
    },
    set: (val)=> {
      this.i = val
    },
    run: () => {
      console.log('runing')
    },
    jump: ()=> {
      console.log('jumping')
    }
  }
  return {
    facade: (args)=>{
      _private.set(args.val);
      _private.get();
      if(args.run){
        _private.run()
      }
    }
  }
})()

module.facade({run:true,val:10}) // 10 runing


工厂模式

用于创建对象的接口。根据传入工厂的类型,可以创建出特定类型的对象。这种模式常见的实现通常是利用类或类的静态方法
class UserPerson {
  constructor(name = '', task = '') {
    this.name = name
    this.task = task
  }
}

class userPersonFactory extends UserPerson {
  constructor(name, viewPage) {
    super(name, viewPage)
  }
  create(role) {
    switch (role) {
      case 'teacher': 
        return new userPersonFactory( '老师', '教书' );
        break;
      case 'student':
        return new userPersonFactory( '学生', '学习' );
        break
      default:
        throw new Error('找不到你想要的')
    }
  }
}
let UPF = new userPersonFactory()
let teacher = UPF.create('teacher')
// userPersonFactory {name: "老师", task: "教书"}
let student = UPF.create('student')
// userPersonFactory {name: "学生", task: "学习"}
let principal = UPF.create('principal')
// Uncaught Error: 找不到你想要的

如果任何问题,欢迎指正,特别感谢!!!!!!