面向对象的几种设计模式
1.面向对象的概念
其实面向对象是相对于面向过程而言,通俗来说就是创建对象,每个对象有自身的属性和方法,对象.属性 对象.方法 实际上这已经是一个面向对象的过程了,面向过程,是指执行一件事的流程,一步接着一步进行,举个例子来说,比如你去烧菜,面向过程的执行就是,你先要去买菜,然后你要去洗菜,然后烧菜等一系列具体的步骤,而对于面向对象而言,把你当做一个对象,买菜是一个对象,烧菜也是一个对象,你首先会传递消息,你要用菜,菜才就会出现,至于菜是怎么来的,买的还是偷得,那就不需要你知道.......等你洗好会菜会发送消息表明现在要烧菜,菜就会烧好,至于菜是如何烧的,过程如何,你也不需要知道,其实面向过程会细究每一步的执行过程,而面向对象不会细究。
----例子有点不恰当,面向对象的概念本身十分的抽象,只能慢慢体会
2 面向对象的设计模式
一.普通模式
普通模式比较繁琐,一个对象一个实例,
普通创建对象的方法,缺陷:
- 如果创建多个对象会比较繁琐,效率低
- 实例与原型之间,没有任何办法,可以看出有什么联系。
例如:
var people=new Object();
people.name="张三";
peoole.food="苹果";
people.eat=function(){
alert(this.name+"喜欢吃"+this.food)
}
people.eat())//张三喜欢吃苹果
var people1=new Object();
people1.name="李四";
peoole1.food="香蕉";
people1.eat=function(){
alert(this.name+"喜欢吃"+this.food)
}
people1.eat()//李四喜欢吃香蕉
//若有100个对象,则需要创建100次,不利于实际的开发
二 工厂模式
这种模式比较简单,其实就是在函数中创建一个对象,给对象添加属性及其属性值或属性方法然后在讲这个对象用return返回出来(return 是关键)
- 创建过程类似于工厂生产产品的过程,即:原材料--加工--产品...
- 解决了多次重复创建多个对象的麻烦。
- 问题:
- 创建出的实例之间没有内在的联系,不能反映出它们是同一个原型对象的实例。
- 创建对象的时候没有使用 new 关键字
- 会造成资源浪费,因为每生成一个实例,都增加一个重复的内容,多占用一些内存。
function create(name,food){
var people=new Object() //原材料;
people.name=nane
people.food=food
people.eat=function(){
alert(this.name+"喜欢吃"+this.food)
}//加工过程
return people;//产品
}
var people 1=create("小丸子",“海鲜”);//不用new关键字创建
var people2=create("小李","红烧肉");
people1.eat()
people2.eat()
//这种模式的缺点就是内存消耗大
people1==people2 //false,占用不同的内存空间
注意:上面提到一定工厂模式一定要有返回值
如果没有返回,则返回错误如下
三. 构造函数模式
- new 调用的函数为构造函数,构造函数和普通函数区别仅仅在于是否使用了new来调用。
- 所谓“构造函数”,就是专门用来生成“对象”的函数。它提供模板,作为对象的基本结构。
- 构造函数内部使用了this变量。对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例对象上。
- instanceof 验证原型对象与实例对象之间的关系。
- 使用call和apply方法实现对象的冒充
- 问题:浪费内存--使用构造函数每生成一个实例,都增加一个重复的内容,多占用一些内存。这样既不环保,也缺乏效率
new关键字能改变this的作用域
关键采用this关键字,对于this的理解,见ttps://www.cnblogs.com/yanhaijing/p/3685309.html(比较厉害的大牛)
function People(name,food){ //构造函数名首字母要大写,小写不会错,但习惯大写
this.name=name ;
this.food=food;
this.eat=function(){
alert(this.name+"喜欢吃"+this.food)//此处this指的是windows对象
}
}
var people1=new people("张三","苹果");
var people2=new people("李四","香蕉");
people1.eat()
people1==people2 //false 占用不同的内存空间
小总结:首先函数名首字母应该大写
与工厂模式不同的是,不需要在函数内部使用关键字new,两者相同的是都消耗很多内存
new关键字会改变this的作用域。this为当前调用的对象
创建完成构造函数后需要new一个实例化的对象赋值给一个变量,然后可以通过这个变量来调用构造函数里面的属性以及方法
构造函数模式可以传递参数
四 原型构造模式
构造函数都会有一个prototype(原型)属性,这个属性其实就是一个指针,它指向了一个对象,在这个对象里包含了可以共享给实例化对象的所有属性及方法
1.第一种写法
function People(){} //定义一个空函数
People.prototype.name="张三";
People.prototype.food="葡萄";
People.prototype.eat=function(){
alert(this.name+"喜欢吃"+this.food)
} //利用prototype属性来添加属性值和方法
var people1=new People();//创建实例化对象
var people2=new People();
people1.eat();
people1.eat==people2.eat //true; 判断是否是相同内存
alert(people1.constructor) //返回构造函数
2 第二种写法
function People(){}
People.prototype={
name:"小米",
food:" 火锅",
job :["IT","销售"],
eat:function(){
alert(this.name+"喜欢吃"+this.food)
}
}
var people1=new People();
people1.job.push("金融");
var people2=new People();
people2.job.push("服务");
alert(people1.job) //弹出为 IT ,销售,金融,服务
alert(people2.job) //弹出为 IT ,销售,金融,服务(由于两者地址相同,所以无论哪一方在向数组中添加,都会全部显示出来)
小总结:原型模式过于呆板,内容定义只能唯一,如果改变其中的属性值,则全部都会改变,没有使用this活泼,内存如果想修改其中一个实例化对象的属性或方法另一个实例对象也会随改变,这并非我们想要的结果,所以就会诞生了混合模式。
补充:
- prototype方式定义的方式,函数不会拷贝到每一个实例中,所有的实例共享prototype中的定义,节省了内存。
- Prototype模式的验证方法
- isPrototypeOf()这个方法用来判断,某个proptotype对象和某个实例之间的关系。
- hasOwnProperty()每个实例对象都有一个hasOwnProperty()方法,用来判断某一个属性到底是本地属性,还是继承自prototype对象的属性。
- in运算符in运算符可以用来判断,某个实例是否含有某个属性,不管是不是本地属性。in运算符还可以用来遍历某个对象的所有属性。
- 对象的constructor属性用于返回创建该对象的构造函数.
- 原型方式的问题:
- 构造函数没有参数。使用原型方式,不能通过给构造函数传递参数来初始化属性的值
- 属性指向的是对象,而不是函数时。函数共享不会造成问题,但对象却很少被多个实例共享,如果共享的是对象就会造成问题
五 混合模式(构造函数模式+原型模式)
//构造函数模式可以传递参数,而且使用this关键字,活动性很强,但消耗内存过多
//原型模式消耗内存小,但活动性很差,因此两者合并,当需要传递参数时,则使用构造函数,当需要执行方法时,使用原型模式,
这是目前最为常用的创建对象的方式。
这种概念非常简单,即用构造函数定义对象的所有非函数属性,用原型方式定义对象的函数属性(方法)。结果是,所有函数都只创建一次,而每个对象都具有自己的对象属性实例。
此外,组合模式还支持向构造函数传递参数,可谓是集两家之所长。
在所接触的JS库中,jQuery类型的封装就是使用组合模式来实例的!!!
function People(name,food){
this.name=name;
this.food=food;
}
People.prototype={
eat:function(){
alert(this.name+"喜欢吃"+this.food)
}
}
var people1=new People("小明","鸡蛋");
var people2=new People(“张三”,“水饺”)
people1.eat();
people2.eat();
people1.eat==people2.eat //true (eat属性属于原型模式,内存相同)
people1.name==people2.name //flase (name属于构造函数属性,内存不同)
六 动态模式
function People(name,food){
this.name=name;
this.food=food;
if(typeof this.eat!='function'){
alert("程序开始");
People.prototype.eat=function(){
alert(this.name+"喜欢吃"+this.food)
}
}
}
var people1=new People("小明","鸡蛋");
var people2=new People("小红","饺子");
people1.eat()
people2.eat();
//执行结果图:
有执行结果图看出动态模式更好的让我们避免创建对象多次初始化
详细代码见:(明天上传github)
有理解不正确的地方,希望大神们指点!
我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=1v9cvnavta0pn
posted on 2018-08-23 16:44 xu-qianqian 阅读(10895) 评论(0) 编辑 收藏 举报