代码要写成别人看不懂的样子(四)

本文介绍了JavaScript中的三种设计模式:建造者模式用于复杂对象的构建,通过步骤化创建;原型模式利用对象克隆实现类的快速实例化,减少性能开销;单例模式确保类只有一个实例,常用于管理全局资源。文中还探讨了单例模式的延时加载(惰性单例)应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

  上节我们一块学习了工厂相关的设计模式,可以方便的帮我们创建类或者实例。本节我们换个角度,不关心产出什么实例,我们来研究一下实例生产的过程。

  这里有个问题,为什么要关注生产过程,我们要的不都是最后的实例对象吗?话是没错,但是有些实例太复杂了,我们需要一步一步划分好功能,依次创建。才能完成最终对象的创建。

  举个例子,我们现在想要一套房子,房子是一个对象没错,我们还要关心这个房子有没有卧室,厨房怎么样,客厅大不大等等。那么这些关注点,都是需要我们创建的。

一、建造者模式

  关注建造细节,下面我们创建一个简历的构造函数。

//创建人类
var Human = function(param) {
	//技能
	this.skill = param && param.skill || '保密';
	//兴趣爱好
	this.hobby = param && param.hobby || '保密';
}
//类人原型方法
Human.prototype = {
	getSkill: function() {
		renturn this.skill;
	},
	getHobby: function() {
		renturn this.hobby;
	}
}
//实例化姓名类
var Named = fucntion(name) {
	var that = this;
	//构造器
	//构造函数解析姓名的姓与名
	(function(name, that) {
		if(name.indexOf(' ') > -1) {
			that.firstName = name.slice(0, name.indexOf(' '));
			that.secondName = name.slice(name.indexOf(' '));
		}
	}) (name, that);
}
//实例化职位类
var Work = function(work) {
	var that = this;
	//构造器
	//构造函数中通过传入的职位特征来设置相应职位以及描述
	(function(work, that) => {
		switch(work) {
			case 'code':
				that.work = '工程师';
				that.workDescript = '沉迷编程无法自拔';
				break;
			case 'UI':
			case 'UE':
				that.work = '设计师';
				that.workDescript = '设计是一种艺术';
				break;
			case 'teach':
				that.work = '教师';
				that.workDescript = '我分享,我快乐';
				break;
			default :
				that.work = work;
				that.workDescript = '对不起,我们还不清楚职位的相关描述';
		}
	}) (work, that);
}
//更换期望的职位
Work.prototype.changeWork = function(work) {
	this.work = work;
}
//更改对职位的描述
Work.prototype.changeDescript = function(setence) {
	this.workDescript = setence;
}

  我们的最终目的是创建一位应聘者,创建过程需要用到上面抽象的三个类,这时候需要一个建造者类,在建造者类中,我们需要通过对三个类的组合调用,创建出一个完整的应聘者对象。

/******
 * 应聘者建造者
 * 参数 name : 姓名(全名)
 * 参数 work : 期望职位
 */
var Person = function(name, work) {
    //创建应聘者缓存对象
    var _person = new Human();
    //创建应聘者姓名解析对象
    _person.name = new Named(name);
    //创建应聘者期望职位
    _person.work = new Work(work);
    return _person;
}

  上面,我们通过三部分来创建一位应聘者。

var person = new Person('xiao ming', 'code');

  建造者模式与工厂最大的不同,就是建造者会参与具体的创建,干涉建造细节,生成的对象,也更复杂。

二、原型模式

  接下来要介绍的设计模式,是整个语言的灵魂,原型模式。

  原型模式指的是:用原型实例指向创建对象的类,使用于创建新的对象的类共享原型对象的属性以及方法。

  举个例子,我们现在创建一个轮播图对象,不同的轮播图效果不一样,有左右滑动的,还有上下滑动的,另外渐变的轮播图也有。

//图片轮播类
var LoopImages = function(imgArr, container) {
	this.imagesArray = imgArr; //轮播图片数组
	this.container= container; //轮播图片容器
	this.createImage = function() {} //创建轮播图片
	this.changeImage = function() {} //切换下一张图片
}
//上下滑动切换类
var SlideLoopImg = function(imgArr, container) {
	//构造函数继承图片轮播类
	LoopImages.call(this, imgArr, container);
	//重写继承的切换下一张图片方法
	this.changeImage = function() {
		console.log('SlideLoopImg changeImage function');
	}
}
//渐隐切换类
var FadeLoopImg = function(imgArr, container, arrow) {
	LoopImages.call(this, imgArr, container);
	//切换箭头私有变量
	this.arrow = arrow;
	this.changeImage = function() {
		console.log('FadeLoopImg changeImage function');
	}
}

  创建一个显隐轮播图片来测试

var fadeImg = new FadeLoopImg([
	'01.jpg',
	'02.jpg',
	'03.jpg',
	'04.jpg'
], 'slide', [
	'left.jpg',
	'right.jpg'
])
fadeImg.changeImage();

  上面代码已经实现了我们需要的功能,但是还有一部分可以优化,比如 LoopImage 作为基类,始终是要被子类继承的,那么把一些方法写到父类的构造函数里就会存在一部分性能问题,因为每次子类继承都要创建一次父类,如果父类里面有很多耗时操作,那么每次创建都会有很大的性能开销,这时候如果把这些耗时操作放到父类的原型上,那么就会节约一大部分性能。

//图片轮播类
var LoopImages = function(imgArr, container) {
	this.imagesArray = imgArr; //轮播图片数组
	this.container= container; //轮播图片容器
	//下面两部分我们移到原型当中,这样就不会每次实例化父类的时候都执行这些耗时操作了
	//this.createImage = function() {} //创建轮播图片
	//this.changeImage = function() {} //切换下一张图片
}
LoopImages.prototype = {
	//创建轮播图片
	createImage: function() {
		console.log('LoopImages createImage function');
	} ,
	//切换下一张图片
	changeImage : function() {
		console.log('LoopImages changeImage function');
	} 
}
//上下滑动切换类
var SlideLoopImg = function(imgArr, container) {
	//构造函数继承图片轮播类
	LoopImages.call(this, imgArr, container);
}
SlideLoopImg.prototype = new LoopImages();
//重写继承的切换下一张图片
SlideLoopImg.prototype.changeImage = function() {
	console.log('SlideLoopImg changeImage function');
}

//渐隐切换类
var FadeLoopImg = function(imgArr, container, arrow) {
	LoopImages.call(this, imgArr, container);
	//切换箭头私有变量
	this.arrow = arrow;
}
FadeLoopImg.prototype = new LoopImages();
FadeLoopImg.prototype.changeImage = function() {
	console.log('FadeLoopImg changeImage function');
}

  原型对象还有一个特点,由于原型对象是一个共享的对象,那么不管父类的实例还是子类的实例,都是对它的指向引用,如果原型对象进行扩展,那么无论是子类还是父类,都会继承下来。所以在扩展的时候,一定要慎重。

LoopImages.prototype.getImageLength = function() {
	return this.imagesArray.length;
}
FadeLoopImg.prototype.getContainer = function() {
	return this.getContainer ;
}
console.log(fadeImg.getImageLength);
console.log(fadeImg.getContainer);

三、单例模式

  接下来一起学习最常用的一种模式,一个人的狂欢。单例模式只允许实例化一次对象类。这种模式的出现,是为了更好的管理我们书写的方法,比如 A 写了一个 getElement 的方法, B 也想写,但是命名又不能一样,这就需要我们对自己的方法进行整理归类,比如我们定义一个自己的命名空间 MySelf

var Myself = {
	getElement: function(id) {
		return document.getElementById(id)
	},
	changeType: function(id, key, value) {
		this.getElement(id).style[key] = value;
	}
}

  上面的代码,就是我们自己的小型代码库,任何我们用到的方法都可以放到这个里面去,当我们想要使用的时候,通过 Myself.getElement 就可以。有了 Myself ,这个命名空间,我们就不用担心会和别人的命名冲突。 JQuery 就是前辈们的一个命名空间,里面有着很多方便我们使用的方法。当我们整理的比较好的时候,也可以发布自己的代码库供别人使用。

单例模式妙用

  单例模式还有一个妙用,就是用来管理静态变量。由于在es6之前,JS 中并没有 static 这个关键字,所以是没有静态变量的,但是我们可以手动实现静态变量的功能。

  所谓静态变量,就是指那些,可以访问,但是不能修改的变量。

var Conf = (
	//私有变量
	var conf = {
		MAX_NUM: 100,
		MIN_NUM: 1,
		COUNT: 1000
	}
	//返回取值器方法
	return {
		//取值器方法
		get: function(name) {
			return conf[name] ? conf[name] : null;
		}
	}
)();

var count = Count.get('COUNT');
console.log(count); //1000

惰性单例

  有时候单例对象需要延迟创建,所以还有一种延迟创建的单例模式。

//惰性载入单例
var = LazySingle = (function() {
	//单例实例引用
	var _instance = null;
	//单例
	function Single() {
		/*这里定义私有属性和方法*/
		return {
			publicMethod: function() {},
			publicProperty: '10'
		}
	}
	//获取单例对象接口
	return function() {
		//如果为创建单例,则创建单例
		if(!_instance) {
			_instance = Single();
		}
		//返回单例
		return _instance;
	}
})();

console.log(LazySingle().publicProperty) //1.0

  到这里,我们已经介绍完了所有关于“创”,“建”,类型的设计模式,从最开始的工厂相关模式,到后面的建造者,原型,单例,这部分包含的功能可以涵盖我们代码的大部分区域,各位同学自己在编码的时候,可以多试试每种模式,我个人的建议是,先按住一个,然后往死里用,合适不合适都这样用,等到什么时候快用吐了,你就真的掌握这种思想了。

  




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值