设计模式,工具库,框架,架构区别:
- 设计模式: 它是一套编目分明,广为人知,可复用的代码经验总结。
- 工具库: 一些常用方法的集合,例如jquery,underscore,这些方法通常是没有联系的
- 框架: 一套半成品代码,它里面也支持一些方法,这些方法之间是有联系的
- 架构: 一套大型项目的设计思路
设计模式的分类及作用:
- 创建型设计模式:解决了创建对象时候的问题
- 简单工厂模式 ✔︎
- 工厂方法模式 ✔︎
- 抽象工厂模式
- 创建者模式
- 原型模式
- 单例模式 ✔︎
- 结构型设计模式:解决了对象和类组合在一起时候的问题
- 外观模式
- 适配器模式
- 适配器模式
- 代理模式
- 装饰模式
- 桥接模式
- 组合模式
- 享元模式
- 行为型设计模式:解决了对象和类耦合,职责之间的问题
- 模板方法模式 ✔︎
- 观察者模式 ✔︎
- 状态模式
- 策略模式 ✔︎
- 职责链模式
- 命令模式
- 访问者模式
- 调停者模式
- 备忘录模式 ✔︎
- 迭代器模式
- 解释器模式
面向对象设计原则
- 单一职责原则
- 开闭原则
- 里氏替代原则
- 依赖注入原则
- 接口分离原则
- 迪米特原则
- 组合/聚合复用原则
创建型工厂模式
1.工厂模式
应用场景
网页端存储token,支不支持h5的localstorage,一个工厂的两个产品
1.1 简单工厂
function factory(name,sex,age){
return {
name: name,
sex: sex,
age: age
}
}
factory('zs','男',18)
factory('ww','女',16)
1.2 工厂方法模式
function Tiger (type,name,age) {
this.type = type;
this.name = name;
this.age = age;
this.beharie= function() {
console.log('tiger')
}
}
function Cat (type,name,age) {
this.type = type;
this.name = name;
this.age = age;
this.beharie= function() {
console.log('cat')
}
}
// 动物通用类
function Animal (type,name,age) {
this.type = type;
this.name = name;
this.age = age;
}
// 定义一个方法来管理上面两个类
function FactoryMethod(type,name,age){
if(type==='tiger'){
return new Tiger(type,name,age)
} else if(type==='cat'){
return new Cat(type,name,age)
} else {
return new Animal(type,name,age)
}
}
// 实例化
var tiger = FactoryMethod('tiger','lh',10);
var cat = FactoryMethod('cat','xmm',3);
var dog = FactoryMethod('dog','bigdog',6)
function FruitMaker() {
}
FruitMaker.prototype.make = function(type,meta) {
if(typeof this.[type] === 'functon') {
var func = this[type];
func.prototype = FruitMaker.prototype;
return new func(meta)
} else {
throw '很抱歉,工厂不能生产这个产品'
}
}
// 扩展生产线
FruitMaker.prototype.extend = function (obj) {
for(var key in obj) {
this.[key] = obj[key];
}
}
FruitMaker.prototype.extend({
'Apple': function (meta) {
console.log('苹果汁',meta)
},
'Pear': function (meta) {
console.log('梨汁',meta)
}
})
// 实例化
var maker = new FritMaker();
var appleObj = maker.make('Apple','苹果,水')
console.log(appleObj.constructor.name)
var pearObj = maker.make('Pear','梨子,水')
console.log(pearObj.constructor.name)
1.3 原型模式
1.4 继承模式
继承种类:
- 类式继承(原型继承)
// 定义基类
function People(name,sex,age) {
this.name = name;
this.sex = sex;
this.age = age;
}
// 基类的原型定义方法
People.prototype.sayHi = function(){
return '姓名'+this.name
}
// 定义子类
function Doctor(name,sex,age,country) {
this.name = name;
this.sex = sex;
this.age = age;
this.country = country
}
// 类式继承: 子类的原型指向父类的实例化
Doctor.prototype = new People();
// 修正子类的构造函数
Doctor.prototype.constructor = Doctor
// 定义子类的方法
Doctor.prototype.behavior = function (){
return '救死扶伤'
}
// 实例化一个子类对象
var d = new Doctor('终南山', '男',60,'中国')
d.sayHi();
d.behavior();
// 实例化一个父类对象
var p = new People('zs','女',18)
d.sayHi(); //
d.behavior(); //报错
2.构造函数继承(apply或call方法)(不是真正的继承,不能访问原型方法)
// 定义基类
function People(name,sex,age) {
this.name = name;
this.sex = sex;
this.age = age;
}
// 基类的原型定义方法
People.prototype.sayHi = function(){
return '姓名'+this.name
}
// 定义子类
function Doctor(name,sex,age,country) {
// 不是真正的继承,只改变了调用对象,不可以调用原型方法
People.apply(this, arguments);
this.country = country
}
// 定义子类的方法
Doctor.prototype.behavior = function (){
return '救死扶伤'
}
// 实例化一个子类对象
var d = new Doctor('终南山', '男',60,'中国')
d.sayHi(); //报错,不能调用
d.behavior();
// 实例化一个父类对象
var p = new People('zs','女',18)
d.sayHi(); //
d.behavior(); //报错
3.组合式继承(类式继承+构造函数式继承)
// 定义基类
function People(name,sex,age) {
this.name = name;
this.sex = sex;
this.age = age;
}
// 基类的原型定义方法
People.prototype.sayHi = function(){
return '姓名'+this.name
}
// 定义子类
function Doctor(name,sex,age,country) {
// 不是真正的继承,只改变了调用对象,不可以调用原型方法
People.apply(this, arguments);
this.country = country
}
// 类式继承: 子类的原型指向父类的实例化
Doctor.prototype = new People();
// 修正子类的构造函数
Doctor.prototype.constructor = Doctor
// 定义子类的方法
Doctor.prototype.behavior = function (){
return '救死扶伤'
}
// 实例化一个子类对象
var d = new Doctor('终南山', '男',60,'中国')
d.sayHi();
d.behavior();
// 实例化一个父类对象
var p = new People('zs','女',18)
d.sayHi(); //
d.behavior(); //报错
4.寄生式继承
// 定义基类
function People(name,sex,age) {
this.name = name;
this.sex = sex;
this.age = age;
}
// 基类的原型定义方法
People.prototype.sayHi = function(){
return '姓名'+this.name
}
// 定义子类
function Doctor(name,sex,age,country) {
// 不是真正的继承,只改变了调用对象,不可以调用原型方法
People.apply(this, arguments);
this.country = country
}
// 类式继承会在原型中,存在几个无用的属性undefind,
// 寄生式继承:定义一个方法,实现去除原型中的空参数
function extent(Child,Parent){
// 创建一个空的类
var F = function (){}
// 空类的原型指向父类实例化对象
F.prototype = Parent.prototype;
// 子类的原型指向空类的实例化对象
Child.prototype = new F();
// 修正构造函数指向子类
Child.prototype.constructor = Child;
}
extent(Doctor, People)
// 定义子类的方法
Doctor.prototype.behavior = function (){
return '救死扶伤'
}
// 实例化一个子类对象
var d = new Doctor('终南山', '男',60,'中国')
d.sayHi();
d.behavior();
// 实例化一个父类对象
var p = new People('zs','女',18)
d.sayHi(); //
d.behavior(); //报错
5.组合寄生式寄生(寄生式继承+组合式继承)
2.单列模式
概念: 保证一个类只有一个实例(通过指定的构造函数,无论创建多少次对象,都只有一个)
场景: 只需要有一个对象的时候(登录/注册)
作用:
- 模块间通信
- 系统中某个类的对象只能存在一个
- 保护自己的属性和方法
注意事项
- 注意this的使用
- 闭包容易造成内存泄漏
- 注意new的成本
实现方式
- 全局变量
- 静态属性
- 优化(即时函数)
- 闭包-惰性函数
js实战
// 最终效果
function Tool() {}
var t1 = new Tool()
var t2 = new Tool()
var t3 = new Tool()
var t4 = new Tool()
// t1,t2,t3,t4返回同一个对象
// 全局变量方式
var instance = null;
function Tool() {
if(instance) {
return instance;
}
instance = this;
this.name = 'zs';
this.age = '18';
}
var t1 = new Tool()
var t2 = new Tool()
var t3 = new Tool()
var t4 = new Tool()
t1===t2;t3===t4;
// 缺点:使用全局变量,变量污染
// 优化 即时函数
(function(w) {
var instance = null;
function Tool() {
if(instance) {
return instance;
}
instance = this;
this.name = 'zs';
this.age = '18';
}
w.Tool = Tool;
})(window)
var t1 = new Tool()
var t2 = new Tool()
var t3 = new Tool()
var t4 = new Tool()
t1===t2;t3===t4;
// 闭包-惰性函数
fuction Tool() {
var instance = this;
var oldPrototype = Tool.prototype;
this.name = 'zs'
this.age = 18;
// 惰性函数(函数只会被执行一次,后面直接调用)
Tool = function () {
return instance;
}
Tool.prototype = oldPrototype;
instance = new Tool();
instance.constructor = Tool;
return instance;
}
var t1 = new Tool()
var t2 = new Tool()
t1 === t2;
3.观察者模式(promise前置知识——4.发布订阅和观察者模式)
4.备忘录模式
5.命名空间模式
6.策略模式
var Celue = {
slow: function(distance) {
console.log('慢速,耗时',distance*2,'小时')
},
normal: function(distance) {
console.log('正常,耗时',distance,'小时')
},
fast: function(distance) {
console.log('快速,耗时',distance/2,'小时')
},
}
function PersonRun(from, to) {
this.from = from;
this.to = to;
}
PersonRun.prototype.run = function(celue) {
celue(this.to - this.from)
}
var p = new PersonRun(0, 20);
p.run(Celue.slow)
p.run(Celue.normal)
p.run(Celue.fast)
7.模版模式
function Fruit() {
}
Fruit.prototype.make = function () {
// 1. 烧水
this.wather();
// 2. 材料
this.cailiao();
// 3.搅拌
this.jiaoban();
// 4.晾凉
this.cool();
}
Fruit.prototype.wather = function (){
console.log('烧水')
}
Fruit.prototype.cailiao = function (){
console.log('材料')
}
Fruit.prototype.jiaoban = function (){
console.log('搅拌')
}
Fruit.prototype.cool = function (){
console.log('晾凉')
}
function Apple(){}
Apple.prototype = new Fruit()
Apple.prototype.cailiao = function() { // 重写不一样的方法
console.log('苹果')
}
var apple = new Apple();
console.log(apple)
apple.make();
8.命令模式
// 点餐人员 关注:菜单
// 厨房老大 关注:分配
// 厨师 关注:菜单
var cook1 = {
name: '王小儿',
make: function(foodType) {
switch(foodType) {
case 'tudou':
console.log(this.name,'做土豆');
break;
case 'jidan':
console.log(this.name,'做鸡蛋');
break;
case 'fanqie':
console.log(this.name,'做番茄');
break;
default:
console.log('不会做!');
break;
}
}
}
var cook2 = {
name: '王大儿',
make: function(foodType) {
switch(foodType) {
case 'tudou':
console.log(this.name,'做土豆加辣椒');
break;
case 'jidan':
console.log(this.name,'做鸡蛋加辣椒');
break;
case 'fanqie':
console.log(this.name,'做番茄加辣椒');
break;
default:
console.log('不会做!');
break;
}
}
}
// 菜单
var foodList = ['tudou','jidan', 'fanqie'];
// 厨师长
function MakFoodCommand(cook, foodType){
this.cook = cook;
this.foodType = foodType;
}
MakFoodCommand.prototype.execute = function(){
this.cook.make(this.foodType)
}
// 做菜命令
var commands = [];
for(var i = 0; i<foodList.length;i++) {
var command = null;
if(i % 2 === 0) {
command = new MakFoodCommand(cook1, foodList[i])
} else {
command = new MakFoodCommand(cook2, foodList[i])
}
commands.push(command)
}
commands.forEach(function(cmd){
console.log(cmd);
cmd.execute()
})