封装
封装目的
- 定义变量不会污染外部
- 能够作为一个模块调用
- 遵循开闭原则
什么是好的封装
- 变量外部不可见
- 调用接口使用
- 留出扩展接口
封装对象时的三种设计模式
创建一个对象的模式
工厂模式
目的:方便我们大量创建对象
应用场景:当某一个对象需要经常创建的时候
例:如分页器,提示窗
基本结构
// 工厂模式就是写一个封装了大量对象的方法,只需调用这个方法,就能拿到你要的对象
function Factory(type) {
switch (type) {
case 'type1':
return new Type1();
case 'type2':
return new Type2();
case 'type3':
return new Type3();
}
}
示例(多彩弹窗,JQ源码)
// 多彩的弹窗
// 需求:项目有一个弹窗需求,弹窗有多种,他们之间存在内容和颜色上的差异
// 工厂模式1.0
(function(){
//信息弹窗
function infoPop(){
}
// 确认弹窗
function confirmPop(){
}
// 取消弹窗
function cancelPop(){
}
function pop(type,content,color){
// 如果new pop()
if(this instanceof pop) {
var s = new this[type](content, color);
} else {
return new pop(type, content, color);
}
switch(type) {
case 'infoPop':
return new infoPop(content,color);
case 'confirmPop':
return new confirmPop(content,color);
case 'cancelPop':
return new cancelPop(content,color);
}
}
window.pop = pop;
})()
// 工厂模式2.0
(function(){
function pop(type,content,color){
// 如果new pop();健壮性
if(this instanceof pop) {
var s = new this[type](content, color);
return s;
} else {
return new pop(type, content, color);
}
}
// 可扩展性
pop.prototype.infoPop=function(){
console.log('infoPop');
}
pop.prototype.confirmPop=function(){
}
pop.prototype.cancelPop=function(){
}
window.pop = pop;
})()
pop('infoPop', 'hello', 'red');
// 源码示例-jquery
// 需求:jQuery需要操作dom,每一个dom都是一个jq对象
(function(){
var jQuery = function( selector, context ) {
// 此处如果new jQuery();会产生递归,无限循环
return new jQuery.fn.init( selector, context);
}
jQuery.fn=jQuery.prototype={ // 让fn=原型链
init:function(){
}
}
jQuery.fn.init.prototype = jQuery.fn; // 让jQuery.fn.init的原型链 = fn = jQuery的原型链
jQuery.extend = jQuery.fn.extend = function() {// JQ的拷贝扩展
}
jQuery.extend({
});
window.$ = window.jQuery = jQuery;
})()
建造者模式
目的:需要组合出一个全局对象
应用场景:当要创建单个、庞大的组合对象时
例:如轮播图
// 把一个复杂的类各个部分,拆分成独立的类,然后再在最终类里组合到一块,final为最终给出去的类
// 模块1
function Mode1() {
}
// 模块2
function Mode2() {
}
// 最终的使用类
function Final() {
this.mode1 = new Mode1();
this.mode2 = new Mode2();
}
示例(编写一个编辑器插件、Vue的初始化)
// 编写一个编辑器插件
// 需求:有一个编辑器插件,初始化的时候需要配置大量参数,而且内部功能很多
//定义最终类
function Editor(){
this.initer = new initHtml();
this.fontControll = new fontControll();
this.stateControll = new stateControll();
}
//html初始模块:样式,dom渲染
function initHtml(domStyle){
this.template='<div style={{editorStyle}}><div></div><div><textarea style={{areaSyle}}/></div></div>';
}
initHtml.prototype.initStyle=function(){
}
initHtml.prototype.renderDom=function(){
}
//字体:颜色,大小
function fontControll(){
};
fontControll.prototype.changeColor=function(){
}
fontControll.prototype.changeFontsize=function(){
}
//状态:保存,回滚,前进
function stateControll(){
this.state = [];
this.nowstate = 0;
}
stateControll.prototype.saveState=function(){
}
stateControll.prototype.stateBack=function(){
var state = this.state[this.nowstate - 1];
this.fontControll.changeColor(state.color);
this.fontControll.changeFontsize(state.color);
}
stateControll.prototype.stateGo=function(){
}
window.Editor=Editor;
// Vue的初始化
// 需求:vue内部众多模块,而且过程复杂
function Vue (options) {
if (!(this instanceof Vue)) {// 判断是否new vue
console.warn('Vue is a constructor and should be called with the `new` keyword');
}
this._init(options);
}
initMixin(Vue);
stateMixin(Vue);
eventsMixin(Vue);
lifecycleMixin(Vue);
renderMixin(Vue);
export function install (_Vue) {
if (Vue && _Vue === Vue) {
if (process.env.NODE_ENV !== 'production') {
console.error(
'[vuex] already installed. Vue.use(Vuex) should be called only once.'
)
}
return
}
Vue = _Vue
applyMixin(Vue)
}
保障对象只有一个
单例模式
目的:需要确保全局只有一个对象
应用场景:为了避免重复新建,避免多个对象存在互相干扰
// 通过定义一个方法,使用时只允许通过此方法拿到存在内部的同一实例化对象
let Singleton = function(name) {
this.name = name
}
Singleton.getInstance = function(name) {
if(this.instance) {
return this.instance;
}
return this.instance = new Singleton(name);
}
示例(写一个数据存储对象 Store,vue-router)
// 写一个数据存储对象
// 需求:项目中有一个全局的数据储存者,这个储存者智能有一个,不然后会需要进行同步,增加复杂度。
//vue
function Store(){ // 作为构造函数使用的 store ,规范约定应使用Pascal case命名【Store】 ;
if(Store.install){
return Store.install;
}
this.store={
}
Store.install=this;
}
Store.install=null;
var s1 = new Store();
var s2 = new Store();
s1.store.a = 1;
console.log(s2)
// vue-router
// 需求:vue-router必须保障全局有且只有一个,否则的话会错乱。
let _Vue;//vue变量
function install (_Vue) {
if (install.installed && _Vue === Vue) return
install.installed = true
_Vue = Vue// 未new过,就付一下值
}
vue.use// 会调用vue.install()
总结
1. 如果你写的模块,需要大量创建类似对象——工厂模式;
2. 需要创建一个需要大量参数,且内部模块庞大——建造者模式;
3. 防止重复注册,防止多个对象互相干扰——单例模式;