设计模式-观察者模式

介绍

  • 发布 & 订阅
  • 一对多

UML类图

  • 传统UML类图
    设计模式-观察者模式_第1张图片
  • 简化后UML类图
    设计模式-观察者模式_第2张图片

代码演示

// 主题,保存状态,状态变化之后触发所有观察者对象
class Subject {
    contructor() {
        this.state = 0;
        this.observers = []
    }
    getState() {
        return this.state
    }
    setState(state) {
        this.state = state
        this.notifyAllObservers()
    }
    notifyAllObservers() {
        this.observers.forEach(observer => {
            observer.update()
        })
    }
    attach(observer) {
        this.observer.push(observer)
    }
}

// 观察者
class Observer {
    constructor(name, subject) {
        this.name = name
        this.subject = subject
        this.subject.attach(this)
    }
    update() {
        console.log(`${this.name} update, state: ${this.subject.getState()}`);
    }
}

// 测试
let s = new Subject()
let o1 = new Observer('o1', s)
let o2 = new Observer('o2', s)
let o3 = new Observer('o3', s)

s.setState(1)

场景

  • 网页事件绑定
<button id="btn1">btn</button>
<script>
$('#btn1').click(function(){
    console.log(1)
})
$('#btn1').click(function(){
    console.log(2)
})
$('#btn1').click(function(){
    console.log(3)
})
</script>
  • Promise
function loadImg(src) {
    var promise = new Promise(function (resolve, reject){
        var img = document.createElement('img')
        img.onload = function () {
            resolve(img)
        }
        img.onerror = function() {
            reject('图片加载失败')
        }
        img.src = src
    })
    return promise
}

var src = 'https://www.imooc.com/static/img/index/logo_new.png'
var result =  loadImg(src);
result.then(function(img) {
    console.log('width', img.width)
    return img
}).then(function(img){
    console.log('height', img.height)
})
  • jQuery callbacks
var callbacks = $.Callbacks()
callbacks.add(function(info){
    console.log('fn1', info)
})
callbacks.add(function(info){
    console.log('fn2', info)
})
callbacks.add(function(info){
    console.log('fn3', info)
})
callbacks.fire('gogogo')
callbacks.fire('fire')
  • nodejs自定义事件
const EventEmitter = require('events').EventEmitter
const emitter1 = new EventEmitter()
emitter1.on('some', () => {
    // 监听some事件
    console.log('some event is occured 1')
})
emitter1.on('some', () => {
    // 监听some事件
    console.log('some event is occured 2')
})

// 触发some事件
emitter1.emit('some')
const EventEmitter = require('events').EventEmitter
const emitter = new EventEmitter()
emitter.on('shonName', name => {
    console.log('event occured', name)
})
emitter.emit('showName', 'zhangsan') // emit时候可以传递参数过去
const EventEmitter = require('events').EventEmitter

// 任何构造函数都可以继承EventEmitter的方法 on emit
class Dog extends EventEmitter {
    constructor(name) {
        super()
        this.name = name
    }
}

var simon = new Dog('simon')
simon.on('bark', function(){
    console.log(this.name, 'barked')
})
setInterval(() => {
    simon.emit('bark')
}, 500)
// Stream用到了自定义事件
var fs = require('fs')
var readStream = fs.createReadStream('./data/file1.txt') // 读取文件的Stream

var length = 0
readStream.on('data', function(chunk) {
    length += chunk.toString().length
})
readStream.on('end', function() {
    console.log(length)
})
// readline用到了自定义事件
var readline = require('readline');
var fs = require('fs')
var rl = readline.createInterface({
    input: fs.createReadStream('./data/file1.txt')
});
var lineNum = 0
rl.on('line', function(line) {
    lineNum++
});
rl.on('close', function() {
    console.log('lineNum', lineNum)
});

其他场景

  • nodejs中:处理http请求;多进程通讯
function serverCallback(req, res) {
    var method = req.method.toLowerCase() // 获取请求的方法
    if (method === 'get') {
        // 省略3行,上文代码示例中处理GET请求的代码
    }
    if (method === 'post') {
        // 接收 post 请求的内容
        var data = ''
        req.on('data', function(chunk){
            // 一点一点接收内容
            data += chunk.toString()
        })
        req.on('end', function() {
            // 接收完毕,将内容输出
            res.writeHead(200, {'Content-type': 'text/html'})
            res.write(data)
            res.end()
        })
    }
}
// parent.js
var cp = require('child_process')
var n = cp.for('./sub.js')
n.on('message', function(m){
    console.log('PARENT got message:' + m)
})
n.send({hello: 'work'})

// sub.js
process.on('message', function(m){
    console.log('CHILD got message: ' + m)
})
process.send({foo: 'bar'})
  • vue和React组件生命周期触发
class Login extends React.Component {
    constructor(props, context) {
        super(props, context);
        this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);
        this.state = {
            checking: false
        }
    }
    render() {
        return (
            <div>
                <Header title="登录" history={this.props.history} />
            </div>
        )
    }
    componentDidMount() {
        // 判断是否已经登录
        this.doCheck()
    }
}
  • vue watch
var vm = new Vue({
    el: '#demo',
    data: {
        firstName: 'Foo',
        lastName: 'Bar',
        fullName: 'Foo Bar'
    },
    watch: {
        firstName: function(val) {
            this.fullName = val + ' ' + this.lastName
        },
        lastName: function(val) {
            this.fullName = this.firstName + ' '  + val  
        },
    }
})

设计原则验证

  • 主题和观察者分离,不是主动触发而是被动监听,两者解耦
  • 符合开放封闭原则

你可能感兴趣的:(设计模式,设计模式,观察者模式)