【JavaScript设计模式】W3CSchool教程阅读笔记

Design Patterns

概念

  • DRY(Dont Repeat Yourself)
  • GoF(四人帮Gang of Four)提出23种设计模式
  • 设计模式是用来设计面向对象的模式
  • 面向对象三大特性:封装、继承、多态
  • 接口:若干抽象方法的集合;对高层隐藏底层实现
  • 面向对象设计SOLID原则
    • 单一职责原则 Single Responsibility
      • 一个类只负责一项职责
    • 开放封闭原则 Open Closed
      • 一个软件实体(类、模块、函数)应该开放扩展,关闭修改
      • 软件实体尽量在不修改原有代码的基础上进行扩展
    • 里式替换原则 Liskov Substitution
      • 所有引用父类的地方必须能透明地使用其子类的对象
      • 子类是特殊的父类,子类可以替换父类
      • Square 算不算 Rectangle
    • 接口隔离原则 Interface Segregation
      • 使用多个专门的接口,而不是使用单一的接口
      • 子类只实现他需要的方法
    • 依赖倒置原则 Dependency Inversion
      • 高层模块不应该依赖低层模块
      • 二者都应该依赖其抽象
      • 抽象不应该依赖细节,细节应该依赖抽象
      • 针对接口编程,而不是针对实现编程

Creational:5

namedescriptionClass/Object
Factory Method工厂方法Class
Abstract Factory抽象工厂Object
Builder建造者
Prototype原型
Singleton单例

Structural:7

namedescriptionClass/Object
Adapter适配器Class
Bridge桥接
Composite组合
Decorator装饰器
Facada外观
Flyweight享元模式
Proxy代理

Behavioral:11

namedescriptionClass/Object
Interpreter解释器Class
Template Method模板方法
Chain of Responsibility响应链Object
Command命令
Iterator迭代器
Mediator中介者
Observer观察者
State状态
Strategy策略
Visitor访问者

JavaScript设计模式

1. 构造器模式Consructor
function Car(type, price){
	this.type = type;
	this.price = price;
	
	this.toString = function(){
		return this.type + ":" + this.price;
	}
}
2. 模块化模式
  • 命名空间
  • 私有变量
// 购物车
var basketModule = (function(){
	var basket = [];
	return {
		getItemCount: function(){
			return basket.length;
		},
		addItem: function(item){
			basket.push(item);
		},
		clear: function(){
			basket.length = 0;
		},
		getTotal: function(){
			var len = this.getItemCount();
			var total = 0;
			while(len--){
				total += basket[len].price;
			}
			return total;
		}
	}
}())
  • 私有成员扩展性不行。一次性定义完成,后续无法更改。
  • 无法对私有变量打补丁
3. 暴露模块模式
  • 启发式模块模式
  • 为私有属性/成员提供公有方法/函数 set/get
  • 无法为公有方法打补丁(在外部访问不到私有属性)
4. 单例模式
  • 单例模式限制一个类只能有一个实例化对象
var mySingleton = (function(){
	var Instance;
	function init(){
		var number = 10;
		return {
			publicMethod: function(){
				return number;
			}
		}
	}
	return {
		getInstance: function(){
			if(!Instance){
				Instance = init();
			}
			return Instance;
		}
	}
}())
5. 观察者模式
  • 松耦合
// 被观察者
function Subject(){
	this.state = 0;
	this.observers = [];
}
Subject.prototype.addObserver = function(observer){
	this.observers.push(observer);
}
Subject.prototype.addObservers = function(observers){
	this.observers = this.observers.concat(observers);
}
Subject.prototype.removeObserver = function (observer){
	let index = this.observers.indexOf(observer);
	if(index > -1){
		this.observers.splice(index, 1);
	}
}
Subject.prototype.changeState = function(){
	this.state++;
	this.broadcast();
}
Subject.prototype.broadcast = function(){
	this.observers.forEach(o => o.update(this.state))
}
// 观察者
function Observer(){
	this.update = function(value){
		console.log("观察到了:" + value);
	}
}
Observer.prototype.changeUpdate = function(fun){
	this.update = fun;
}

var observer = new Observer();
var subject = new Subject();
var ob = new Observer();
ob.changeUpdate(v => console.log("加倍:" + v * 2));
subject.addObservers([observer, ob]);
subject.changeState();
  • 发布订阅,增加了中间件(Publisher -> Event Channel -> Subscriber)
  • 不是一个对象直接调用另一个对象的方法,而是通过订阅另一个对象的一个特定的任务或活动,在这个任务或活动出现时得到通知
  • 订阅者的功能崩溃,发布者无法感知
  • 订阅者彼此之间没有感知
  • 发布者和订阅者不需要互相了解,他们只需要在中间层消息代理(消息队列)的帮助下通信
  • 在发布者/订阅者模式中,组件与观察者完全分离。在观察者模式中,主体和观察者松散耦合
  • 观察者模式主要是已同步方式实现的,既当发生某些事件时,主题调用观察者的相关方法。调用权在被观察者,调用实现在观察者内部。
  • 发布订阅模式主要以异步方式实现。最终处理权在订阅者。
// 调度中心
function EventChannel(){
	this.events = {};
}
// 接受订阅者的注册信息, 记录需要推送的订阅者
EventChannel.prototype.addEventListener = function(type, handler){
	if(!(this.events[type] instanceof Array)){
		this.events[type] = [];
	}
	this.events[type].push(handler);
}
// 接受发布者的发布消息, 发布来自发布者的信息
EventChannel.prototype.publish = function(type, ...args){
	if(this.events[type] instanceof Array){
		this.events[type].forEach(h => h(args));
	}
}
// 实例
var eventChannel = new EventChannel();
// 订阅者(一个函数,一个行为)
function subscriber(e){
	console.log(e);
}
eventChannel.addEventListener('oneEvent', subscriber);
// 订阅者2
var sub = {
	'oneEvent': function(e){
		console.log('I received ' + e);
	},
	'anotherEvent': function(e){
		console.log("It's time to do " + e);
	}
}
eventChannel.addEventListener('oneEvent', sub.oneEvent);
eventChannel.addEventListener('anotherEvent', sub.anotherEvent);
// 发布者
var publisher = {
	publish: function(type){
		eventChannel.publish(type, Math.random());
	}
}
publisher.publish('oneEvent');
publisher.publish('anotherEvent');
6. 中介者模式
  • 中央集权?(消息转发者,中间层的权力下降,谁发送谁接受的决定权被分散到每个协同者中去,自行决定)
  • 中介模式是观察者模式中的共享被观察者
  • 降低通信复杂度,网状->星型
  • 协同者向中介发送消息,最终处理权在于中介
  • MVC
// 中介
function Mediator(){
	this.colleagues = {};
}
Mediator.prototype.register = function(clg){
	clg.mediator = this;
	this.colleagues[clg.name] = clg;
	return clg;
}
// 转发,将协同者发送来的消息转发给协同者指定的同事
Mediator.prototype.forward = function(msg, from, to){
	if(to){
		// 单发
		to.receive(msg, from);
	}else{
		// 群发
		for(let c in this.colleagues){
			this.colleagues[c].receive(msg, from);
		}
	}
}
// 协同者
function Colleague(name){
	this.name = name;
	this.mediator = null;
}
Colleague.prototype.send = function(msg, to){
	this.mediator.forward(msg, this, to);
}
Colleague.prototype.receive = function(msg, from){
	console.log(from.name + ' to ' + this.name + ': ' + msg);
}

var mediator = new Mediator();
var A = mediator.register(new Colleague('A'));
var B = mediator.register(new Colleague('B'));
var C = mediator.register(new Colleague('C'));
var D = mediator.register(new Colleague('D'));
A.send('Just for B', B);
B.send('For all');

7. 原型模式
  • 使用对象创建对象
  • 对象直接继承自其他对象
var obj = Object.create(proto);
  • 问题:hasOwnProperty()
8. 命令模式
  • 消除事务性的不可分指令
  • 把调用对象和实现操作的对象隔离开,将发出命令和执行命令的职责分开
  • Command/ConcreteCommand/Invoker/Receiver
// 计算器
function add(a,b){return a + b;} // plus
function sub(a,b){return a - b;} // subtraction
function mul(a,b){return a * b;} // multiply
function div(a,b){return a / b;} // division
// 命令抽象类,接口,只提供方法名,不管具体实现
var Command = function(execute, undo, value){
	this.execute = execute;
	this.undo = undo;
	this.value = value;
}
Command.prototype.log = function(flag){
	console.log(this[flag].name + this.value);
}
// 命令具体类
var addCommand = function(value){
	return new Command(add, sub, value);
}
var subCommand = function(value){
	return new Command(sub, add, value);
}
var mulCommand = function(value){
	return new Command(mul, div, value);
}
var divCommand = function(value){
	return new Command(div, mul, value);
}
// 计算器类,模块模式
var Calculator = function(){
	var current = 0;
	var commands = []; // 命令队列
	return {
		execute: function(cmd){
			current = cmd.execute(current, cmd.value);
			commands.push(cmd);
			cmd.log('execute');
		},
		undo: function(){
			let cmd = commands.pop();
			current = cmd.undo(current, cmd.value);
			cmd.log('undo');
		},
		getCurrentValue: function(){
			return current;
		}
	}
}

var calc = new Calculator();
calc.execute(addCommand(100));
9. 外观模式facade
  • 门面模式
  • 选择性的暴露方法
  • Facade — Subsystem
  • 为内部子系统简化沟通管道,隐藏内部细节
  • 便利函数
  • 经典应用: 兼容不同的浏览器API形成的方法
var addEvent = function(element, event, handler){
	if(element.addEventListener){
		element.addEveneListener(event, handler);
	}else if (element.attachEvent){
		element.attachEvent("on" + event, handler);
	}else{
		element["on" + event] = handler;
	}
}
10. 工厂模式
// 内部实现,不暴露
function Warrior(){}
Warrior.prototype.attack = function(){
	console.log('Close Attack');
}
function Mage(){}
Mage.prototype.attack = function(){
	console.log('Magic Damage');
}
function Archer(){}
Archer.prototype.attack = function(){
	conosle.log('Remote Attack');
}
// 外部,客户端,杂货铺
var CharacterFactory = {
	createCharacter: function(type){
		switch(type){
			case 'Warrior': return new Warrior();
			case 'Mage': return new Mage();
			case 'Archer': return new Archer();
			default: return new Warrior();
		}
	}
}
// 访问
var warrior = CharacterFactory.createCharacter('Warrior');
  • 工厂方法
  • Creator — Product
  • 父类希望延迟创建到派生类
  • 依赖倒置
// 各自类实现各自的工厂方法
var MageFactory = function(){}
MageFactory.prototype.createCharacter = function(){
	return new Mage();
}
// 外部,客户端,专卖店
var mf = new MageFactory();
// 访问
var mage = mf.createCharacter();
  • 抽象工厂
  • 创建一系列相关产品
// 武器弓
function Bow(){}
// 工厂方法
var ArcherFactory = function(){}
ArcherFactory.prototype.createCharacter = function(){
	return new Archer();
}
ArcherFactory.prototype.createWeapon = function(){
	return new Bow();
}
// 不光卖鞋,顺带的衣服帽子全套
11. Mixin模式
  • 织入模式
  • 复用
// 可以被共享的方法
var myMixin = {
	up: function(){
		console.log('up');
	},
	down: function(){
		console.log('down');
	},
	stop: function(){
		console.log('stop');
	}
}
// 待扩展的类/对象
function Car() {
	this.left = function(){console.log('left');}
	this.right = function(){console.log('right');}
}
// 1. 覆盖原型
Car.prototype = myMixin;
var car = new Car();
// 2. 增强原型
for(let key in myMixin){
	Car.prototype[key] = myMixin[key];
}
12. 装饰模式
  • 子类划分
  • 向一个系统中现有的类动态添加行为的能力
  • 装饰本身并不关心类的基础功能,只是将自身拷贝到超类之中
  • 在一个简单基础对象上逐步添加能够 提供附加功能的 装饰对象
  • 向一个基础对象添加(装饰)属性或方法
// 基础对象
function Hero(){
	this.attackDamage = function(){
		return 60;
	}
	this.abilityPower = function(){
		return 20;
	}
	this.physicalResistance = function(){
		return 30;
	}
	this.spellResistance = function(){
		return 10;
	}
}
// Decorator
function BFSword(hero){
	var bfad = 35; // 暴风大剑提供35攻击
	var ad = hero.attackDamage();
	hero.attackDamage = function(){
		return ad + bfad;
	}
}
function UselessStick(hero){
	var usap = 60; // 无用大棒提供60法强
	var ap = hero.abilityPower();
	hero.abilityPower = function(){
		return ap + usap;
	}
}
// 装饰
var Demacia_Power = new Hero();
Demacia_Power.attackDamage(); // 60
BFSword(Demacia_Power);
Demacia_Power.attackDamage(); // 95
BFSword(Demacia_Power);
Demacia_Power.attackDamage(); // 130
BFSword(Demacia_Power);
Demacia_Power.attackDamage(); // 165
BFSword(Demacia_Power);
Demacia_Power.attackDamage(); // 200
UselessStick(Demacia_Power);
Demacia_Power.abilityPower(); // 80
  • 接口
  • 抽象装饰者
  • 装饰基础类,而不是生成许多类
13. 享元模式Flyweight
  • 轻量级
  • 优化重复、缓慢和低效数据共享
  • 内部状态和外部状态
  • 对象池
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值