设计模式
2019-04-02 本文已影响0人
磨人的磨磨虫
1.单例模式
保证全局只有一个实例,节省资源,类似java的静态类 static,一般用到的地方有历史记录、线程池等等
let Singleton=function(){
this.name=1
}
//因为javascript 没有静态类的标识 故用闭包保持唯一性 外部无法访问instance
Singleton.getInstance=(function(){
let instance=null
return function(){
if(!instance ){
instance=new Singleton()
}
return instance
}
})()
let s1=Singleton.getInstance()
let s2=Singleton.getInstance()
console.log(s1===s2)//true
console.log(s1.name)//1
s1.name=2
console.log(s1.name)//2
console.log(s2.name)//2
2.策略类
比如算法,各种算法封装在策略类,各种方法的使用交给环境类
看代码:
let strategy={
//冒泡排序 逐个调换位置
A(numbers){
for(let i=0;i<numbers.length;i++){
for(let j=0;j<numbers.length;j++){
let itemNext=numbers[j+1]
let item=numbers[j]
if(itemNext<item){
numbers[j+1]=item
numbers[j]=itemNext
}
}
}
return numbers
},
//选择排序 每次循环把最小的放入前置位
B(numbers){
for(let i=0;i<numbers.length;i++){
let itemI=numbers[i]
for(let j=i+1;j<numbers.length;j++){
let itemJ=numbers[j]
if(itemI>itemJ){
numbers[i]=itemJ
numbers[j]=itemI
itemI=itemJ
}
}
}
return numbers
}
}
let content=name=>{
let numbers=[1,3,5,6,1,3,4,6,5]
return strategy[name](numbers)
}
console.log(content('A'))
console.log(content('B'))
3.代理模式
高度解耦,对象保护,易修改,因为是代理,所以会慢一点
示例代码:
let myImg={
setSrc(img,src){
img.src=src
}
}
let proxyImg={
setImg(imgNode,src){
//实现图片懒加载
myImg.setSrc(imgNode,'默认图.png')//占位图片
let img=new Image()
imgNode.onLoad=function(){
myImg.setSrc(imgNode,src)
}
img.src=src//真正要加载的产品图片
}
}
let imgNode=document.crateElement('img')
let imgUrl='产品图.png'
document.body.append(imgUrl)
proxyImg.setImg(imgNode,imgUrl)
4.迭代器模式
迭代器模式是指提供一种方法顺序访问一个集合对象的各个元素,使用者不需要了解集合对象的底层实现。
不太清楚其用途~
let Iterator=obj=>{
let current=0;
let next = ()=>current+=1
let end = ()=>current>=obj.length
let get = ()=>obj[current]
return{
next,
end,
get
}
}
let myIter = Iterator([1, 2, 3]);
while(!myIter.end()) {
console.log(myIter.get()) myIter.next();
}
5.订阅发布模式
订阅-发布模式定义了对象之间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都可以得到通知。
event.js
class Event{
constructor(){
this._cbs={}
}
//订阅
on(key,fn){
if(typeof fn != "function"){
return false
}
this._cbs = this._cbs || {};
(this._cbs[key] = this._cbs[key] || []).push(fn)
}
//发布
emit(){
let _cbs=this._cbs
let key=Array.prototype.shift.apply(arguments)
let affair =_cbs[key]||[]
if(!affair||affair.length<1){
return false
}
for(let fn of affair){
fn.apply(null,arguments)
}
return true
}
//销毁
off(key,fn){
this._cbs = this._cbs || {}
// all
if (!arguments.length) {
this._cbs = {}
return true
}
var callbacks = this._cbs[key]
if (!callbacks) return
// remove all handlers
if (arguments.length === 1) {
delete this._cbs[key]
return true
}
// remove specific handler
var cb
for (var i = 0, len = callbacks.length; i < len; i++) {
cb = callbacks[i]
if (cb === fn || cb.fn === fn) {
callbacks.splice(i, 1)
break
}
}
return true
}
}
export default Event
//a.js
import Event from event.js
let e=new Event()
e.on('one',v=>{
console.log('订阅')
console.log(v)
})
e.emit('one',1000)
e.off('one')
e.emit('one',1000)
6.工厂模式
工厂方法模式的实质是“定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。” 简单来说:就是把new对象的操作包裹一层,对外提供一个可以根据不同参数创建不同对象的函数。
class Dog{
run(){
console.log('狗')
}
}
class Cat{
run(){
console.log('猫')
}
}
class Animal{
constructor(name){
name = name.toLocaleLowerCase()
switch(name){
case 'cat':
return new Dog()
case 'dog':
return new Cat()
default:
console.log('没有哦')
}
}
}
let ss=new Animal('cat')
ss.run()
7.组合模式
用小的子对象构造更大的父对象,而这些子对象也由更小的子对象构成 单个对象和组合对象对于用户暴露的接口具有一致性,而同种接口不同表现形式亦体现了多态性
// 文件类
class File {
constructor(name) {
this.name = name || "File";
}
add() {
throw new Error("文件夹下面不能添加文件");
}
scan() {
console.log("扫描文件: " + this.name);
}
}
// 文件夹类
class Folder {
constructor(name) {
this.name = name || "Folder";
this.files = [];
}
add(file) {
this.files.push(file);
}
scan() {
console.log("扫描文件夹: " + this.name);
for (let file of this.files) {
file.scan();
}
}
}
let home = new Folder("用户根目录");
let folder1 = new Folder("第一个文件夹"),
folder2 = new Folder("第二个文件夹");
let file1 = new File("1号文件"),
file2 = new File("2号文件"),
file3 = new File("3号文件");
// 将文件添加到对应文件夹中
folder1.add(file1);
folder2.add(file2);
folder2.add(file3);
// 将文件夹添加到更高级的目录文件夹中
home.add(folder1);
home.add(folder2);
// 扫描目录文件夹
home.scan();
8.享元模式
享元模式:运用共享技术来减少创建对象的数量,从而减少内存占用、提高性能。
class ObjectPool{
constructor(){
this._pool=[]
}
create(obj){
return this._pool.length===0?
new obj(this):
this._pool.shift()
}
recover(obj){
return this._pool.push(obj);
}
// 对象池大小
size() {
return this._pool.length;
}
}
// 模拟文件对象
class File {
constructor(pool) {
this.pool = pool;
}
// 模拟下载操作
download() {
console.log(`+ 从 ${this.src} 开始下载 ${this.name}`);
setTimeout(() => {
console.log(`- ${this.name} 下载完毕`); // 下载完毕后, 将对象重新放入对象池
this.pool.recover(this);
}, 100);
}
}
/****************** 以下是测试函数 **********************/
let objPool = new ObjectPool();
let file1 = objPool.create(File);
file1.name = "文件1";
file1.src = "https://download1.com";
file1.download();
let file2 = objPool.create(File);
file2.name = "文件2";
file2.src = "https://download2.com";
file2.download();
setTimeout(() => {
let file3 = objPool.create(File);
file3.name = "文件3";
file3.src = "https://download3.com";
file3.download();
}, 200);
setTimeout(
() =>
console.log(
`${"*".repeat(50)}\n下载了3个文件,但其实只创建了${objPool.size()}个对象`
),
1000
);