面向对象编程
面向对象编程( Object-oriented programming, OOP) 是一种程序设计范型。它将对象作为程序的基本单元,将程序和数据封装其中,以提高程序重用性、灵活性和扩展性。
-
封装
将属性和方法进行封装var Book= function(id, bookname, price) { this.id= id; this.bookname= bookname; this.price =price; this.getBookName(){ return this.bookname } }
-
继承
- 类式继承
将父类的实例化赋值给子类prototype
function Parent(title){ this.title = title } function Son(title){ } Son.prototype = new Parent()
缺点:
1、由于子类通过其原型 prototype对父类实例化,继承了父类。所以说父类中的共有属性要是引用类型,就会在子类中被所有实例共用,因此各个子类的实例更改子类原型从父类构造函数中继承来的共有属性就会直接影响到其他子类,比如你看下面的代码。function Superclass() { this.books =['JavaScript','html','css']; } function Subclass(){} Subclass.prototype =new Superclass(); var instancel =new Subclass(); var instance2 =new Subclass() ; console.log(instance2.books ); //[”JavaScript”,”html”,”css”] instancel.books.push('设计模式'); console.log(instance2.books) ; //[ "JavaScript ”,” tml ”,” css ”,” 设计模式”]
2、由于子类实现的继承是靠其原型 prototype 对父类的实例化实现的,因此在创建父类的时候 是无法向父类传递参数的,因而在实例化父类的时候也无法对父类构造函数内的属性进行初始化。
- 构造函数继承
在构造函数中用call方法实现,如下:
function Parent(title){ this.title = title } function Son(title){ Parent.call(this,title) }
缺点:
由于这种类型的继承没有涉及原型 prototype ,所以父类的原型方法自然不会被子类继承- 组合继承
也就是上面两种方式的组合,可以过滤掉上面两种方式缺点,但是父类构造函数调用了两遍。
function Parent(title){ this.title = title } function Son(title){ Parent.call(this,title) } Son.prototype = new Parent()
- 原型式继承
其实是类式继承的一种封装,同样存在类式继承的问题
function inheritObj(o) { function F(){} //过渡作用,可以减小开销 F.prototype = o return new F() } Obj = { name: 'test', list: [1,2] } let son = inheritObj(Obj)
- 寄生式继承
其实是原型式继承的封装
function createObj(obj) { // 通过原型继承方式创建新对象 var o = new inheritObject(obj) ; // 拓展新对象 o.getName =function() { console.log(name); } // 返回拓展后的新对象 return o ; }
- 寄生组合式继承
function inheritPrototype(subClass, superclass) { // 复制一份父类的原型副本保存在变量中 var p = inheritObject(superClass.prototype); // 修正因为重写子类原型导致子类的 constructor 属性被修改 p.constructor = subclass; // 设置子类的原型 subclass.prototype = p; }
- 类式继承
-
多态
比如一个方法根据不同的参数做出不同的处理
创建型设计模式
创建型设计模式是一类处理对象创建的设计模式,通过某种方式控制对象的创建来避免基本对象创建时可能导致设计上的问题或增加设计上的复杂度。
- 简单工厂模式
简单工厂模式( Simple Factory ):又叫静态工厂方法,由一个工厂对象决定创建某一种产
品对象类的实例。主要用来创建同一类对象。
// 篮球基类
var Basketball = function () {
this.intro = '篮球盛行于美国'
}
Basketball.prototype = {
getMember : function () {
console.log('每个队伍需要5名队员')
},
getBallSize : function () {
console.log('篮球很大')
}
}
// 足球基类
var Football = function() {
intro = '足球在世界范围内很流行'
}
Football.prototype = {
getMember : function() {
console.log('每个队伍需要 11 名队员')
},
getBallSize : function() {
console.log('足球很大')
}
}
// 运动工厂
var SportsFactory = function(name) {
switch(name) {
case ' NBA ':
return new Basketball();
case ' wordCup ':
return new Football( );
}
}
-
工厂方法模式
工厂方法模式( Factory Method) 通过对产品类的抽象使其创建业务主要负责用于创建多个类产品的实例。
工厂方法模式本意是将实际创建对象工作推迟到子类当中,这样核心类就成了抽象类。// 工厂类 var Factory = function(type, content) { if(this instanceof Factory) { var s = new this[type](content) return s } else { return new Factory(type, content) } } // 工程原型中设置创建所有数据类型数据对象的基类 Factory.prototype = { Java: function (content) {}, Php: function (content) {}, Python: function (content) {} }
-
抽象工厂模式
抽象工厂模式(Abstract Factory) 通过对类的工厂抽象使其业务用于对产品类簇的创建,而不负责创建某一类产品的实例。
抽象类:抽象类是一种声明但不能使用的类,当你使用时就会报错。
// 汽车抽象类,当使用其实例对象的方法时会抛出错误
var Car = function(){};
Car.prototype = {
getPrice : function() {
return new Error ('抽象方法不能调用')
},
getSpeed : function() {
return new Error ('抽象方法不能调用')
}
}
// 抽象类方法提示子类重写抽象方法
抽象工厂方法
// 抽象工厂实现对抽象类的继承
var VehicleFactory = function(subType,superType){
// 判断抽象工厂中是否有该方法
if(typeof VehicleFactory[superType] === 'function'){
// 缓存类
function F(){}
// 继承父类属性和方法
F.prototype = new VehicleFactory[superType]()
// 将子类constructor指向子类
subType.constructor = subType
// 子类原型继承父类
subType = new F()
} else {
// 不存在抽象类抛出错误
throw new Error('未创建该抽象类')
}
}
// 小汽车抽象类
VehicleFactory.Car = function(){
this.type = 'car'
}
VehicleFactory.Car.prototype = {
getPrice : function() {
return new Error ('抽象方法不能调用')
},
getSpeed : function() {
return new Error ('抽象方法不能调用')
}
}
// 公交车抽象类
VehicleFactory.Bus = function(){
this.type = 'Bus'
}
VehicleFactory.Bus.prototype = {
getPrice : function() {
return new Error ('抽象方法不能调用')
},
getSpeed : function() {
return new Error ('抽象方法不能调用')
}
}
// 使用
var BMW = function(price,speed){
this.price = price
this.speed = speed
}
VehicleFactory(BMW,'Car')
BMW.prototype.getPrice(){
return this.price
}
抽象工厂其实是一个实现子类继承父类的方法,在这个方法中我们需要通过传递子类以及要继承父类(抽象类〉的名称,并且在抽象工厂方法中又增加了一次对抽象类存在性的一次判断,如果存在,则将子类继承父类的方法。然后子类通过寄生式继承。继承父类过程中有一个地方需要注意,就是在对过渡类的原型继承时,我们不是继承父类的原型,而是通过 new 关键字复制的父类的一个实例 ,这么做是因为过渡类不应仅仅继承父类的原型方法,还要继承父类的对象属性,所以要通过 new 关键字将父类的构造函数执行一遍来复制构造函数中的属性和方法。
因为抽象工厂方法不需要实例化对象,故只需要一份,因此直接为抽象工厂添加类的属性。
- 建造者模式
建造者模式(Builder ):将一个复杂对象的构建层与其表示层相互分离,同样的构建过程
可采用不同的表示。
// 创建一位人
var Human = function(params){
this.skill = params&¶ms.skill || '保密'
this.hobby = params&¶ms.hobby || '保密'
}
// Human 原型方法
Human.prototype = {
getSkill(){
return this.skill
},
getHobby(){
return this.hobby
}
}
// 实例化姓名类
var Named = function(name) {
var that = this
// 解析姓名
(function(name,that){
that.wholeName = name
if(name.indexOf(' ')>-1){
this.firstName = name.slice(0,name.indexOf(' '))
this.secondName = name.slice(name.indexOf(' '))
}
})(name,that);
}
// 实例化职位类
var Work = function(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('shaoying','code')
- 原型模式
原型模式(Prototype ):原型实例指向创建对象的类,使用于创建新的对象的类共享原
型对象的属性以及方法。
例 轮播图
// 轮播图类
var LoopImages = function(imgArr,container){
this.imageArray = imgArr
this.container = container
}
// 可继承方法
LoopImages.prototype = {
createImage: function(){},
changeImage: function(){}
}
// 上下切换
var SlideLoopImg = function(imgArr,container){
LoopImages.call(this,imgArr,container)
}
SlideLoopImg.prototype = new LoopImages()
// 重写方法
SlideLoopImg.prototype.changeImage = function(){}
- 单例模式
单例模式( Singleton ):又被称为单体模式,是只允许实例化1次的对象类。有时我们也指用对象来规划1个命名空间,井井有条地管理对象上的属性与方法。
关键字:命名空间 静态变量 惰性单例(延迟创建单例)
例子 jquery vue 单页页面应用// 单例 ver Single = { tool: { // 属性方法 }, api: { // 属性方法 } //... } // 惰性单例 var LazySingle = (function(){ ver _single = null ver Single = function(){ var static = { // 静态属性或方法 } return { // 单例属性方法 } } return function(){ if(!single){ single = new Single() } return single } })();
结构型设计模式
结构型设计模式关注于如何将类或对象组合成更大、更复杂的结构,以简化设计。
- 外观模式
外观模式(Facade ):为一组复杂的子系统接口提供一个更高级的统一接口,通过这个接
口使得对子系统接口的访问更容易。在 JavaScript 中有时也会用于对底层结构兼容性做统一封
装来简化用户使用。
// 外观模式实现事件绑定
function addEvent(dom,type,fn){
//对于支持 DOM2 级事件处理程序 addEventListener 方法的浏览
if(dom.addEventListener) {
dom .addEventListener(type , fn , false);
//对于不支持 addEventListener 方法但支持 attachEvent 方法的浏览
}else if(dom.attachEvent) {
dom.attachEvent('on' + type , fn);
//对于不支持 addEventListener 方法也不支持 attachEvent 方法,但支持 on ’事件名’的 浏览器
}else{
dom.['on'+type] = fn
}
}
- 适配器模式
适配器模式( Adapter ):将一个类(对象〉 的接口(方法或者属性〉转化成另外一个接口,
以满足用户需求,使类(对象)之间接口的不兼容问题通过适配器得以解决。
例如参数适配、框架适配等
function(obj){
var arg = { // 设置参数默认值
naem: 'test',
title: ''
// ...
}
for(let key in obj){
arg[key] = obj[key] || arg[key]
}
//...
}
- 代理模式
代理模式 Proxy ):由于一个对象不能直接引用另一个对象,所以需要通过代理对象在这
两个对象之间起到中介的作用。 - 装饰者模式
装饰者模式(Decorator ):在不改变原对象的基础上,通过对其进行包装拓展(添加属性
或者方法〉使原有对象可以满足用户的更复杂需求。
比如装饰器 - 桥接模式
桥接模式 Bridge ):在系统沿着多个维度变化的同时,又不增加其复杂度并已达到解耦// 多维类 // 运动单元 function Speed(x,y){ this.x = x this.y = y } Speed.prototype.run = function(){ console.log('run') } // 着色单元 function Color(cl){ this.color = cl } Color.prototype.draw = function(){ console.log('draw') } // 变形单元 function Shape = function(s){ this.shape = s } Shape.prototype.shape = function(){ console.log('shape') } // 说话单元 function Speek(word){ this.word = word } Speed.prototype.say = function(){ console.log('say') } // 创建球类 function Ball(x,y,c){ this.speed = new Speed(x,y) this.color = new Color(c) } Ball.prototype.init = function(){ this.speed.run() this.color.draw() } // 创建人物类 function People(x,y,w){ this.speed = new Speed(x,y) this.speek = new Speek(w) } People.prototype.init = function(){ this.speed.run() this.speek.say() } //其它类...
- 组合模式
组合模式( Composite ):又称部分·整体模式,将对象组合成树形结构以表示“部分整体”
的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。 - 享元模式
享元模式 Flyweight ):运用共享技术有效地支持大量的细粒度的对象,避免对象间拥有
相同内容造成多余的开销。
相信大家也看累了,给点时间消化下,下一篇将继续介绍剩余的三大设计模式,行为型设计模式、技巧型设计模式和架构型设计模式。