title: 初探设计模式(一)
date: 2020-09-20 14:51:00
tags:
谈到设计模式,我的肤浅认知就是能通过它们写出比较优秀的代码。emmm让我们从菜某教程上找一段比较官方的话解释一下——设计模式(Design pattern),它代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。它是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多大佬们经过相当长的一段时间的试验和错误总结出来滴。今天,我们来结合实践学习几种设计模式吧。
1.工厂模式
工厂,从现实生活中来看它是批量生产相似产品的地方。从代码层面来说工厂就是定义一个方法,该方法可以根据传入的参数去产生不同的对象。
{% codeblock lang:js %}
function factory(id, date, size) {
var obj = new Object();
obj.id = id;
obj.price = price;
obj.size = size;
obj.showPrice = function() {
return this.price;
}
return obj;
}
{% endcodeblock %}
工厂模式是为了解决多个相似对象声明的问题, 它调用的时候不需要使用 new。让我们来结合一个实际场景看一下。
众所周知,一个项目里会有多种类型的弹窗。警告弹窗、成功弹窗、错误弹窗、确认弹窗、取消弹窗等,它们的UI和里边的内容、操作等都可能是不相同的。针对不同的弹窗我们可以来建立一些类。
{% codeblock lang:js %}
function warningModal(text, buttonList) {}
functio successModal(text, buttonList) {}
function submitModal(text, buttonList) {}
//如果直接使用的话就是
let modal = new warningModal(content, color, buttonList);
{% endcodeblock %}
可以看到上面每创建一个弹窗就得写上对应的方法,这里我们可以用工厂方式来改造一下。
{% codeblock lang:js %}
function createModal(type, text, buttonList) {
switch(type) {
case 'warningModal':
return new warningModal(text, buttonList);
case 'successModal':
return new successModal(text, buttonList);
case 'submitModal':
return new submitModal(text, buttonList);
}
}
//调用
let modal = createModal('submitModal', text, buttonList);
{% endcodeblock %}
switch的用法不是很优美,记得之前也被同事吐槽过,那我们就用面向对象来改造一下这个方法吧。我们将创建不同类型的弹窗方法就挂载在这个原型成为实例方法咯。
{% codeblock lang:js %}
function createModal(type, text, buttonList) {
if (this instanceof createModal) {
return new this[type](text, buttonList);
} else {
return new createModal(type, text, buttonList);
}
}
createModal.prototype.warningModal = function (text, color) {}
createModal.prototype.successModal = function (text, color) {}
createModal.prototype.submitModal = function (text, color) {}
{% endcodeblock %}
2.单例模式
单例模式的特点是全局只能有一个实例化对象。
{% codeblock lang:js %}
//单例模式
var SingleEx = function (id) {
this.id = id;
this.instance = null;
}
SingleEx.prototype.getId = funtcion () {
return this.id;
}
//获取实例对象
var getInstance = (function () {
var instance = null;
return function (id) {
if (!instance) {
instance = new SingleEx(id);
}
return instance;
}
}) ();
{% endcodeblock %}
我们可以看到getInstance它会检测是不是有现存的实例对象,从而保证只实例化一次,那么它又有什么应用场景呢。想想我们在对全局的数据对象进行管理的时候,这个对象一定只能有一个,否则的话多个对象来保存数据的话会导致其不同步。是不是很是适合单例模式的场景呢
{% codeblock lang:js %}
function store () {
if (store.instance) {
return store.instance;
}
store.instance = this;
}
let storeObj = new store();
{% endcodeblock %}
基于一个页面理应只有一个路由对象,因为不唯一会造成状态的冲突。那么vue-router也是用到了单例模式的呢。
{% codeblock lang:js %}
//这一段是vue-router的源码的思路qaq
let _Vue;
function install(Vue) {
if(install.hasInstalled && Vue === _Vue) return;
install.hasInstalled = true;
_Vue = Vue;
}
{% endcodeblock %}
那么我们可以通过以上总结出,单例模式的核心思想就是用一个临时变量来记录代码是否已经执行过一次了,如果执行过就不再次执行,而是返回上一次的结果,从而保证多次调用得到的是同一个实例。
3.原型模式
Javascript的原型链就是一个原型模式.我们可以用Oject.create来让一个对象作为原型。
{% codeblock lang:js %}
const object = {
id: 1,
name: 'able',
singing: () => {
}
}
//以object为原型创建一个新的对象
const newObject = Object.create(obj);
{% endcodeblock %}
我们可以通过console得知新的对象的proto和object是完全相等的,新的对象也能拥有object上的属性和方法。最后我们来写一个继承,加深对原型模式的理解吧!
{% codeblock lang:js %}
function People(name,age){
this.name = name || 'xjj';
this.age = age || 3;
}
People.prototype.sleep = function(){
return this.name + this.age + 'fall asleep'
}
function Woman(name,age){
People.call(this,name,age)
}
Woman.prototype = new People();
Woman.prototype.constructor = Woman;
let wonmanObj = new Woman(xj,3);
wonmanObj.sleep();
{% endcodeblock %}
上面写的是比较基础的组合式继承,让Woman.prototype.proto指向父类的prototype,从而能够获取父类的方法和属性。