美文网首页
行为模式-观察者模式(The Observer Pattern)

行为模式-观察者模式(The Observer Pattern)

作者: ZhouMac | 来源:发表于2016-05-18 20:06 被阅读52次

    本文大部分内容翻译至《Pro Design Pattern In Swift》By Adam Freeman,一些地方做了些许修改,并将代码升级到了Swift2.0,翻译不当之处望多包涵。

    观察者模式(The Observer Pattern)

    观察者设计模式定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。


    示例工程

    OS X Command Line Tool工程:

    SystemComponents.swift

    class ActivityLog {
        func logActivity(activity:String) {
            print("Log: \\(activity)")
        }
    }
    
    class FileCache {
        func loadFiles(user:String) {
            print("Load files for \\(user)")
        }
    }
    
    class AttackMonitor {
        var monitorSuspiciousActivity: Bool = false {
            didSet {
                print("Monitoring for attack: \\(monitorSuspiciousActivity)")
            }
        }
    }
    

    ActivityLog类代表系统的事件日志输出;FileCache类代表一个给定的用户的文件加载;AttackMonitor类代表可疑事件发生时的安全服务。

    Authentication.swift

    class AuthenticationManager {
        private let log = ActivityLog()
        private let cache = FileCache()
        private let monitor = AttackMonitor()
        
        func authenticate(user:String, pass:String) -> Bool {
            var result = false
            if (user == "bob" && pass == "secret") {
                result = true
                print("User \\(user) is authenticated")
                // call system components
                log.logActivity("Authenticated \\(user)")
                cache.loadFiles(user)
                monitor.monitorSuspiciousActivity = false
            } else {
                print("Failed authentication attempt")
                // call system components
                log.logActivity("Failed authentication: \\(user)")
                monitor.monitorSuspiciousActivity = true
            }
            return result
        }
    }
    

    AuthenticationManager类代表用密码来认证用户的服务类。可以看出认证成功后会输出成功日志并加载用户的文件,失败后会输出失败日志并输出受攻击的警告。

    main.swift

    let authM = AuthenticationManager()
    authM.authenticate("bob", pass: "secret")
    print("--------------")
    authM.authenticate("joe", pass: "shhh")
    

    运行程序:

    User bob is authenticated
    Log: Authenticated bob
    Load files for bob
    Monitoring for attack: false
    --------------
    Failed authentication attempt
    Log: Failed authentication: joe
    Monitoring for attack: true
    

    理解观察者模式解决的问题

    示例中的代码结构在真正的项目中十分常见,一个事件的发生引起了一系列的其它事件的发生。



    问题发生在操作初始事件的类里(本例中就是AuthenticationManager类),它必须知道触发的其它事件的详细和它们是如何操作的。如果其中的一个触发类做一些修改,那么相应的初始事件类中也要做相应的修改。


    理解观察者模式

    观察者模式通过将它们分成被观察者和观察者来改变这种关系。被观察者持有观察者的集合,当发生改变时就通知它们。



    实现观察者模式

    实现观察者模式的关键是用协议定义观察者和被观察者的协议。

    Observer.swift

    protocol Observer : class {
        func notify(user:String, success:Bool)
    }
    
    protocol Subject {
        func addObservers(observers:Observer...)
        func removeObserver(observer:Observer)
    }
    

    注意到Observer协议的class关键字, 这样做的原因是我们后面要进行对象的比较。

    创建被观察者基类

    我们知道被观察类持有观察者类的集合,所以同时需要GCD并发保护。

    Observer.swift

    import Foundation
    protocol Observer : class {
        func notify(user:String, success:Bool)
    }
    
    protocol Subject {
        func addObservers(observers:Observer...)
        func removeObserver(observer:Observer)
    }
    
    class SubjectBase : Subject {
        private var observers = [Observer]()
        private var collectionQueue = dispatch_queue_create("colQ",DISPATCH_QUEUE_CONCURRENT)
        
        func addObservers(observers: Observer...) {
            dispatch_barrier_sync(self.collectionQueue){[weak self] in
                for newOb in observers {
                    self!.observers.append(newOb)
                }
            }
        }
        
        
        func removeObserver(observer: Observer) {
            dispatch_barrier_sync(self.collectionQueue){[weak self] in
                self!.observers = self!.observers.filter(){
                    $0 !== observer
                }
            }
        }
        
        func sendNotification(user:String, success:Bool) {
            dispatch_sync(self.collectionQueue){ [weak self] in
                for ob in self!.observers {
                    ob.notify(user, success: success)
                }
            }
        }
    }
    

    实现被观察者协议

    Authentication.swift

    class AuthenticationManager : SubjectBase {
        func authenticate(user:String, pass:String) -> Bool {
        var result = false
        if (user == "bob" && pass == "secret") {
            result = true
            print("User \\(user) is authenticated")
        } else {
            print("Failed authentication attempt")
        }
        sendNotification(user, success: result)
        return result
        }
    }
    

    实现观察者协议

    SystemComponents.swift

    class ActivityLog : Observer {
        func notify(user: String, success: Bool) {
            print("Auth request for \\(user). Success: \\(success)")
        }
        
        func logActivity(activity:String) {
            print("Log: \\(activity)")
        }
    }
    
    class FileCache : Observer {
        func notify(user: String, success: Bool) {
            if (success) {
                loadFiles(user)
            }
        }
            
        func loadFiles(user:String) {
            print("Load files for \\(user)")
        }
    }
    
    class AttackMonitor : Observer {
        func notify(user: String, success: Bool) {
                monitorSuspiciousActivity = !success
        }
                
        var monitorSuspiciousActivity: Bool = false {
            didSet {
                print("Monitoring for attack: \\(monitorSuspiciousActivity)")
            }
        }
    }
    

    最后我们再看main.swift:

    let log = ActivityLog()
    let cache = FileCache()
    let monitor = AttackMonitor()
    let authM = AuthenticationManager()
    
    authM.addObservers(log, cache, monitor)
    authM.authenticate("bob", pass: "secret")
    
    print("-----")
    authM.authenticate("joe", pass: "shhh")
    

    运行程序:

    User bob is authenticated
    Auth request for bob. Success: true
    Load files for bob
    Monitoring for attack: false
    -----
    Failed authentication attempt
    Auth request for joe. Success: false
    Monitoring for attack: true
    

    我们再添加观察者就显得很容易了,只要实现观察者协议然后调用addOberservers方法添加观察者就行了。


    观察者模式的变形

    泛化通知类型

    示例中的notify 方法只能接收认证的通知,这其实是很糟糕的一种设计。

    ...
    func notify(user:String, success:Bool)
    ...
    

    下面我们做一些修改,使得它所接受的数据类型和通知类型都可以多样化。

    Observer.swift

    import Foundation
    
    enum NotificationTypes : String {
        case AUTH_SUCCESS = "AUTH_SUCCESS"
        case AUTH_FAIL = "AUTH_FAIL"
    }
    struct Notification {
        let type:NotificationTypes
        let data:Any?
    }
    
    protocol Observer : class {
        func notify(notification:Notification)
    }
    ......
    
    func sendNotification(notification:Notification) {
            dispatch_sync(self.collectionQueue){ [weak self] in
                for ob in self!.observers {
                    ob.notify(notification)
                }
            }
        }
    .......
    

    接着我们修改SystemComponents.swift :

    class ActivityLog : Observer {
        func notify(notification:Notification) {
            print("Auth request for \\(notification.type.rawValue) " + "Success: \\(notification.data!)")
        }
        
        func logActivity(activity:String) {
            print("Log: \\(activity)")
        }
    }
    
    class FileCache : Observer {
        func notify(notification:Notification) {
            if (notification.type == NotificationTypes.AUTH_SUCCESS) {
                loadFiles(notification.data! as! String)
            }
        }
            
        func loadFiles(user:String) {
            print("Load files for \\(user)");
        }
    }
    
    class AttackMonitor : Observer {
        func notify(notification: Notification) {
            monitorSuspiciousActivity = (notification.type == NotificationTypes.AUTH_FAIL)
        }
            
        var monitorSuspiciousActivity: Bool = false {
            didSet {
                print("Monitoring for attack: \\(monitorSuspiciousActivity)");
            }
        }
    }
    

    最后是AuthenticationManager.swift:

    class AuthenticationManager : SubjectBase {
        func authenticate(user:String, pass:String) -> Bool {
            var nType = NotificationTypes.AUTH_FAIL
            if (user == "bob" && pass == "secret") {
                nType = NotificationTypes.AUTH_SUCCESS
                print("User \\(user) is authenticated")
            } else {
                print("Failed authentication attempt")
            }
            sendNotification(Notification(type: nType, data: user))
            return nType == NotificationTypes.AUTH_SUCCESS
        }
    }
    

    运行程序:

    p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px Menlo; color: #ffffff}span.s1 {font-variant-ligatures: no-common-ligatures}
    
    User bob is authenticated
    Auth request for AUTH_SUCCESS Success: bob
    Load files for bob
    Monitoring for attack: false
    -----
    Failed authentication attempt
    Auth request for AUTH_FAIL Success: joe
    Monitoring for attack: true
    

    相关文章

      网友评论

          本文标题:行为模式-观察者模式(The Observer Pattern)

          本文链接:https://www.haomeiwen.com/subject/gopwrttx.html