持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,点击查看活动详情
- 本文主要介绍iOS设计模式中的
观察者模式,观察者模式也叫发布-订阅模式。在我们iOS中KVO也是观察者模式。
1. 什么是观察者模式
我们之前说航空交通需要集中的空中交通管制,有很多的操作员坐在操控塔里盯着自己的雷达屏幕,以确保不会发生空中相撞。飞行员把他们的无线电调到特定的频道,收听(观察)周围的交通状况。如果交通管制员向收听这个频道的飞行员广播了某些预警或警告,飞行员可以用某些行动表示已收到了消息。因此在这一模式中,任何人都知道他们观察哪个交通管制,反过来却不然。
订阅杂志也是这样,当从杂志发行商订阅杂志时候,读者把收货信息提供给发行商,这样有新的杂志就可以第一时间收到,读者不会收到没有订阅的杂志。或者我们在微博上关注某个用户,当她发布动态的时候,我们会第一时间收到通知。
我们把这一思想引入面向对象软件设计中来,用于消除具有不同行为的对象之间的耦合(或者用其他不同的行为来拓展现有的行为)。通过这一个模式,不同对象可以协同工作,同时它们可以被复用于其他地方。我们称这种模式为观察者模式。
观察者模式是一种发布-订阅模型,Observer从subject订阅通知,发生改变后第一时间通知观察者。我们在oc中使用的RAC以及Swift框架中的RXSwift都是大量使用了观察者模式。对于iOS中本身的KVO可以看下我之前的文章KVO原理以及 自定义KVO
观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
2. 什么时候使用观察者模式
以下情形下,可以考虑使用这一模式。
- 有两种
抽象类型相互依赖。将它们封装在各自的对象中,就可以对它们单独进行改变和复用。 - 对一个
对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变。 - 一个对象必须
通知其他对象,而它又不知道其他对象是什么。
3. 代码展示
在iOS中,使用通知和kvo达到观察者模式。我们对对象的setter方法进行监听,添加观察者,当观察对象的属性发生改变触发了setter方法后,通知我们的观察者进行方法的调用,我们之后进行处理。这里只是简单的说明下,具体可以上面提到的文章。
import XCTest
class ObserverRealWorld: XCTestCase {
func test() {
let cartManager = CartManager()
let navigationBar = UINavigationBar()
let cartVC = CartViewController()
cartManager.add(subscriber: navigationBar)
cartManager.add(subscriber: cartVC)
let apple = Food(id: 111, name: "Apple", price: 10, calories: 20)
cartManager.add(product: apple)
let tShirt = Clothes(id: 222, name: "T-shirt", price: 200, size: "L")
cartManager.add(product: tShirt)
cartManager.remove(product: apple)
}
}
protocol CartSubscriber: CustomStringConvertible {
func accept(changed cart: [Product])
}
protocol Product {
var id: Int { get }
var name: String { get }
var price: Double { get }
func isEqual(to product: Product) -> Bool
}
extension Product {
func isEqual(to product: Product) -> Bool {
return id == product.id
}
}
struct Food: Product {
var id: Int
var name: String
var price: Double
/// Food-specific properties
var calories: Int
}
struct Clothes: Product {
var id: Int
var name: String
var price: Double
/// Clothes-specific properties
var size: String
}
class CartManager {
private lazy var cart = [Product]()
private lazy var subscribers = [CartSubscriber]()
func add(subscriber: CartSubscriber) {
print("CartManager: I'am adding a new subscriber: (subscriber.description)")
subscribers.append(subscriber)
}
func add(product: Product) {
print("\nCartManager: I'am adding a new product: (product.name)")
cart.append(product)
notifySubscribers()
}
func remove(subscriber filter: (CartSubscriber) -> (Bool)) {
guard let index = subscribers.firstIndex(where: filter) else { return }
subscribers.remove(at: index)
}
func remove(product: Product) {
guard let index = cart.firstIndex(where: { $0.isEqual(to: product) }) else { return }
print("\nCartManager: Product '(product.name)' is removed from a cart")
cart.remove(at: index)
notifySubscribers()
}
private func notifySubscribers() {
subscribers.forEach({ $0.accept(changed: cart) })
}
}
extension UINavigationBar: CartSubscriber {
func accept(changed cart: [Product]) {
print("UINavigationBar: Updating an appearance of navigation items")
}
open override var description: String { return "UINavigationBar" }
}
class CartViewController: UIViewController, CartSubscriber {
func accept(changed cart: [Product]) {
print("CartViewController: Updating an appearance of a list view with products")
}
open override var description: String { return "CartViewController" }
}
运行结果
CartManager: I'am adding a new subscriber: UINavigationBar
CartManager: I'am adding a new subscriber: CartViewController
CartManager: I'am adding a new product: Apple
UINavigationBar: Updating an appearance of navigation items
CartViewController: Updating an appearance of a list view with products
CartManager: I'am adding a new product: T-shirt
UINavigationBar: Updating an appearance of navigation items
CartViewController: Updating an appearance of a list view with products
CartManager: Product 'Apple' is removed from a cart
UINavigationBar: Updating an appearance of navigation items
CartViewController: Updating an appearance of a list view with products
4. 总结
观察者模式在iOS还是比较常用的一种设计模式,但是一般都是配合一些框架进行使用比如RXSwift,我们数据绑定在taleView上,视图跟随数据进行刷新变化。或者我们表单,监听我们的条件是否满足从而更新按钮的UI状态。本质上也是为了解决数据和我们UI的耦合性问题,从而达到UI复用的效果。