swift设计模式:(二)观察者模式(Observe Pattern)

本文介绍了观察者模式,定义为对象间一对多依赖关系,状态变化时依赖对象自动刷新。通过老板员工示例认识该模式,还介绍了Foundation框架中的通知机制及自定义通知中心的实现,包括原理分析、Subject和Observer实现、通知中心实现及测试用例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

观察者模式

定义:观察者设计模式定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并且自动刷新。
设计原则:为了交互对象之间的松耦合设计而努力。

举例说明:

比如老板在一个办公室里开会,办公室里有部分员工,在办公室的员工就是Observer(观察者),正在开会的老板就是Subject(主题:负责发送通知—Post Notification)。如果其他员工也想成为Observer,那么必须得进入(addObserver)正在开会的会议室成为观察者。员工成功观察者后收到通知得做一些事情吧(doSomething),比如记个笔记神马的。如果此时员工闹情绪,不想听老板开会了,于是通过removeObserver走出了会议室。上面这个过程其实就是观察者模式。

一、通过示例认识观察者模式

场景:使用boss发送通知,员工接受通知

boss和员工显然是一对多的关系,我们将要实现的“类图”如下所示:
在这里插入图片描述

1、图中的SubjectType是 通知者的基类,负责发通知

参数说明
info表示发布的信息
observerArray保存多个观察者的数组,使用数组的原因是由于 Subject:Observers是一对多的关系
函数说明
registerObserver(observer)注册观察者
removeObserver(observer)移除观察者
notigyObserver()通知观察者

图中Boss是SubjectType的子类,继承了父类的所有的所有属性,并重写了父类的三个方法

函数说明
setInfo()负责更新Info信息的时候调用发出通知的方法

2、图中ObserverType 是 观察者的基类

参数说明
info存储接收到的通知信息
函数说明
update()接收到通知后要执行的方法,即boss一发通知,员工就会执行该方法
display()对info字段的信息进行输出

注:把SubjectType 和 ObserverType设计成基类,不利于后期的扩展,或者会在扩展中会产生重复的代码,可以使用接口或者结合其他设计模式,能很好的解决上面的问题。

3、类图的具体实现

上面的Boss负责发通知,Coder 和PM负责监听 Boss发的通知

1)通知者和观察者基类的实现

在SubjectType基类中的observerArray中存储的是ObserverType类型(包括其子类)对象, 即 所有的观察者

//基类
class ObserverType{
    
    //发布的消息
    var info : String = ""
    func update(_ info : String){}
    func display(){}
}
class SubjectType{
    var observersArray : [ObserverType] = [ObserverType]()
    var info : String = ""
    //注册观察者
    func registerObserver(_ observer : ObserverType){}
    //移除观察者
    func removeObserver(_ observer : ObserverType){}
    //通知观察者
    func notifyObserver(){}
}

2)负责发送通知的Boss类的实现

Boss 继承自SubjectType 。
当Boss 执行 setInfo() 方法时,就会调用 notifyObservers()进行通知的发送。
在Boss中的registerObserver()方法用来添加监听者(为了防止重复添加,我们在添加前先进行移除),removeObserver() 则是复杂移除监听者,notifyObservers() 是发送通知并调用观察者相应的方法。

//发出通知的人,也就是通知中心,大Boss
class Boss : SubjectType{
    func setInfo(_ info : String){
        if info != self.info {
            self.info = info
            self.notifyObserver()
        }
    }
    
    override func registerObserver(_ observer: ObserverType) {
        self.removeObserver(observer)
        self.observersArray.append(observer)
    }
    
    override func removeObserver(_ observer: ObserverType) {
        for i in 0..<self.observersArray.count {
            if type(of: observersArray[i]) == type(of: observer){
                self.observersArray.remove(at: i)
                break
            }
        }
    }
    override func notifyObserver() {
        for observer : ObserverType in self.observersArray {
            observer.update(self.info)
        }
    }
}

3)观察者的实现

有两个观察者,分别是 Coder(程序员) 和PM(产品经理),都是ObserverType的子类,重写了 基类的 update()和display()方法。
观察者在观察到 Subject 的info 被改变后,就会执行 update()方法。

//程序员
class Coder : ObserverType{
    override func update(_ info: String) {
        self.info = info
        display()
    }
    override func display() {
        print("程序员收到:\(self.info)")
    }
}
//产品经理
class PM : ObserverType{
    override func update(_ info: String) {
        self.info = info
        display()
    }
    override func display() {
        print("产品经理收到:\(self.info)")
    }
}

4)测试用例

//创建boss
    let bossSubject : Boss = Boss()
    //创建观察者
    let coderObserver : Coder = Coder()
    let PMObserver : PM = PM()
    //添加观察者
    bossSubject.registerObserver(coderObserver)
    bossSubject.registerObserver(PMObserver)
    print(bossSubject.observersArray)
    bossSubject.setInfo("第一次通知")
    //程序员走出了会议室(移除通知)
    bossSubject.removeObserver(coderObserver)
    bossSubject.setInfo("第二次通知")

测试结果为:
第一次发生通知的时候,两个都是观察者,接着 移除了coder的观察者,第二次发通知的时候,就只有pm是观察者了。
在这里插入图片描述

二、Foundation 框架中的通知

Foundation框架是自带一套完成的 观察者模式机制的, 即 通知机制。

1、NotificationCenter 简述

NotificationCenter是Foundation框架通知机制中的通知中心,扮演者调度通知的作用。
Subject 往通知中心发通知,有通知中心统一管理,把发送的消息分发给相应的观察者。
所以通知中心是一个集合,集合中有多个 Subject 和多个 Observer的集合。
通知中心扮演的角色就是将Subject 和 相应的 Observer进行关联。
原理图如下所示:
在这里插入图片描述

2、Foundation 中通知的使用

1)创建 Subject 通知者
有以下几个步骤:
(1)创建消息字典,该字典就是观察者所获取的信息
(2)创建通知 Notification,该通知也是需要发送给 Observer的,通知中包括 Subject 的名称、发送通知的对象,以及创建的消息字典
(3)将 通知 发送给 通知中心 NotificationCenter ,通知中心会根据 通知的信息找到观察此通知的 观察者Observer,并把通知传给每个观察者

Boss扮演的就是Subject

//subject
class Boss : NSObject{
    func sendMessage(_ message : String){
        //1、创建消息字典
        let userInfo = ["message":message]
        //2、创建通知
        let notification = Notification.init(name: Notification.Name(rawValue: "Boss1"), object: nil, userInfo: userInfo)
        //3、发送通知
        NotificationCenter.default.post(notification)
    }
}

2)添加 Observer 观察者
我们需要制定观察者所观察的 Subject,通过其名称来明确观察的对象,还需要指定收到通知后的执行方法,在指定的方法有一个参数,是用来接收发出的 通知Notification 的对象的。
注意:在当前对象释放时,需要移除观察者

//添加observer
class Coder:NSObject{
    func observerBoss(){
        NotificationCenter.default.addObserver(self, selector: #selector(accepteNotification(_:)), name: NSNotification.Name(rawValue: "Boss"), object: nil)
    }
    @objc func accepteNotification(_ notification : Notification){
        let info = notification.userInfo
        print("收到老板通知了:\(String(describing: info!["message"]))")
    }
    deinit {
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "Boss"), object: nil)
    }
}

3)测试用例

let boss = Boss()
    let coder = Coder()
    coder.observerBoss()
    boss.sendMessage("涨工资啦")

测试结果为在这里插入图片描述

三、自定义通知中心

实现一套属于自己的通知机制,调用方式类似于Foundation框架中的通知调用方式,只是命名不同。

1、分析通知机制原理

自定义通知机制的 类“类图”如下所示:
在这里插入图片描述
1)MyCustomNotificationCenter 对应 NotificationCenter
MyCustomNotification 对应 Notification
MySubject 和MyObserver 是为了实现该通知机制所创建的Subject 和Observer

2)通知机制的运作方式
Boss将Notification发送到NotificationCenter,然后NotificationCenter在通过其内部实现机制,将Boss发送过来的Notification发送到Coder。

3)MyCustomNotification

参数说明
name发送通知对象的名称 ,即“Boss”
object上述例子的Boss的对象
userInfo发送给Observer的信息字典

4)MyObserver

参数说明
observer观察者对象
selector观察者对象收到通知后要执行的方法

5)MySubject

参数说明
notification记录要发送的通知
observers是一个数组,存储该subject对应的观察者
函数说明
addCustomObserver添加观察者
removeCustomObserver移除观察者
postNotification发送通知

6)MyCustomNotificationCenter
该类的对象是通过 defaultCenter() 方法获取的单例对象,在该方法中有一个 center 名称的字段,该字段是字典类型, key 对应MySubject 对象指定的name,value对应 Mysubject 对象。
其中也有添加、移除观察者和发送通知等方法。

2、Subject 和 Observer 实现

1)MyCustomNotification

参数说明
name发送通知对象的名称 ,即“Boss”
object上述例子的Boss的对象
userInfo发送给Observer的信息字典
//通知
class MyCustomNotification:NSObject{
    let name : String
    let object : AnyObject?
    let userInfo : [NSObject : AnyObject]?
    
    init(_ name : String, _ object : AnyObject?, _ userInfo : [NSObject:AnyObject]?) {
        self.name = name
        self.object = object
        self.userInfo = userInfo
    }
}

2)MyObserver

参数说明
observer观察者对象
selector观察者对象收到通知后要执行的方法

当收到通知时,就会执行observer的selector方法。

//观察者
class MyObserver:NSObject{
    let observer : AnyObject
    let selector : Selector
    
    init(_ observer : AnyObject, selector : Selector){
        self.observer = observer
        self.selector = selector
    }
}

3)MySubject
MySubject类将Notification与Observers进行关联。
具体说来就是当MySubject收到Notification中,就会遍历其所有的观察者(observers的类型是ObserveArray,其中存储的是MyObserver的对象),遍历观察者时就会去执行该观察者所对应的selector方法。

参数说明
notification存储的就是Subject所要发出的通知
observers数组类型,其中存储的是MyObserver的对象
函数说明
addCustomObserver()往observers数组中添加观察者
removeCustomObserver()移除observers数组中的观察者
postNotification()对observers数组进行遍历取出MyObserver的对象,然后执行该对象中的selector方法,并且将notification作为selector方法的参数
typealias ObserverArray = Array<MyObserver>
//主题
class MySubject : NSObject{
    var notification : MyCustomNotification?
    var observers : ObserverArray
    
    init(_ notification : MyCustomNotification?, _ observers : ObserverArray){
        self.notification = notification
        self.observers = observers
    }
    
    //添加观察者
    func addCustomObserver(_ observer : MyObserver){
        for i in 0..<observers.count {
            if observers[i].observer === observer.observer{
                return
            }
        }
        self.observers.append(observer)
    }
    
    //移除观察者
    func removeCustomObserver(_ observer : MyObserver){
        for i in 0..<observers.count {
            if observers[i].observer === observer.observer{
                observers.remove(at: i)
                break
            }
        }
    }
    
    //发送通知
    func postNotification(){
        for i in 0..<observers.count {
            let myObserver : MyObserver = self.observers[i]
            myObserver.observer.performSelector(inBackground: myObserver.selector, with: self.notification)
        }
    }
}

3、通知中心的实现

通知中心的类的定义如下:

typealias SubjectDictionary = Dictionary<String, MySubject>
class MyCustomNotificationCenter : NSObject{
}

1)模拟系统通知中心的单例获取

private static let singleton = MyCustomNotificationCenter()
    static func defaultCenter()->MyCustomNotificationCenter{
        return singleton
    }
    override init() {
        super.init()
    }

2)通知中心发送通知的过程

对应NotificationCenter.defaultCenter中的postNotification(notification)。

(1)首先会调用getSubjectWithNotifaction(notification)方法来从center中获取可以发送该notification的Subject对象
(2)在getSubjectWithNotifaction(notification)中,如果center中没有可以发送该notification的对象,那么就创建一个MySubject对象,并将该notification赋值给这个新建的MySubject对象,最后将我们创建的这个新的subject添加进center数组中
(3)然后调用该subject对象的postNotification()方法即可

//================通知中心,存储的是Subject对象的集合============
    private var center : SubjectDictionary = SubjectDictionary()
    
    //发出通知
    func postNotification(_ notification : MyCustomNotification){
        //首先会调用getSubjectWithNotifaction(notification)方法来从center中获取可以发送该notification的Subject对象
        let subject = self.getSubjectNotification(notification)
        //然后调用该subject对象的postNotification()方法即可
        subject.postNotification()
    }
    
    //根据notification获取相应的subject对象,没有的话就创建
    func getSubjectNotification(_ notification : MyCustomNotification)->MySubject{
        
        guard let subject = center[notification.name] else {
            //如果center中没有可以发送该notification的对象,那么就创建一个MySubject对象,并将该notification赋值给这个新建的MySubject对象,
            //最后将我们创建的这个新的subject添加进center数组中
            center[notification.name] = MySubject(notification, ObserverArray())
            return self.getSubjectNotification(notification)
        }
        if subject.notification == nil {
            subject.notification = notification
        }
        return subject
    }

3)添加监听者

对应NotificationCenter.defaultCenter中的addObserver()。

(1)首先我们把传入的参数生成MyObserver的对象,
(2)然后通过aName从center字典中获取相应的MySubject对象。如果center中没有对应的MySubject对象,我们就创建该对象,并且将该对象的notification属性暂且指定为nil。
(3)最后调用MySubject类中的addCustomObserver()方法进行观察者的添加。

//添加监听者
    func addObserver(_ observer : AnyObject, _ aSelector : Selector, _ aName : String){
        //首先我们把传入的参数生成MyObserver的对象
        let myObserver = MyObserver(observer, selector: aSelector)
        //通过aName从center字典中获取相应的MySubject对象
        var subject : MySubject? = center[aName]
        
        //如果center中没有对应的MySubject对象,我们就创建该对象,并且将该对象的notification属性暂且指定为nil
        if subject == nil {
            subject = MySubject(nil, ObserverArray())
            center[aName] = subject
        }
        
        //调用MySubject类中的addCustomObserver()方法进行观察者的添加
        subject?.addCustomObserver(myObserver)
    }

4)移除监听者

(1)首先也是通过name从center字典中获取MySubject的对象,(2)然后调用MySubject对象的removeCustomObserver()方法进行移除掉。

//从通知中心移除observer
    func removeObserver(_ observer : AnyObject, _ name : String){
        //首先也是通过name从center字典中获取MySubject的对象
        guard let subject : MySubject = center[name] else {
            return
        }
        //然后调用MySubject对象的removeCustomObserver()方法进行移除掉
        subject.removeCustomObserver(observer as! MyObserver)
    }

4、测试用例

class Boss : NSObject{
    func sendMessage(_ message : String){
        //1、创建消息字典
        let userInfo = ["message":message]
        //2、创建通知
        let notification = MyCustomNotification.init(Notification.Name(rawValue: "Boss2").rawValue, nil, userInfo as [NSObject : AnyObject])
        //3、发送通知
        MyCustomNotificationCenter.defaultCenter().postNotification(notification)
    }
}
//添加observer
class Coder:NSObject{
    func observerBoss(){
        MyCustomNotificationCenter.defaultCenter().addObserver(self, #selector(accepteNotification(_:)), "Boss2")
    }
    @objc func accepteNotification(_ notification : MyCustomNotification){
        let info : Dictionary = notification.userInfo!
        print("收到老板通知了:",info["message" as! NSObject])
    }
    deinit {
        MyCustomNotificationCenter.defaultCenter().removeObserver(self, "Boss2")
    }
}

let boss = Boss()
    let coder = Coder()
    let coder = Coder()
    coder.observerBoss()
    coder.observerBoss()
    boss.sendMessage("涨工资啦")

测试结果与二中测试结果一致。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值