設計模式-行為型模式,觀察者模式(13)


當對象間存在一對多關系時,則使用觀察者模式(Observer Pattern)。比如,當一個對象被修改時,則會自動通知它的依賴對象。觀察者模式屬於行為型模式。

有時,我們希望在一個對象的狀態改變時更新另外一組對象。

 

class Publisher:

    def __init__(self):
        self.observers = []

    def add(self, observer):
        if observer not in self.observers:
            self.observers.append(observer)
        else:
            print('Failed to add: {}'.format(observer))

    def remove(self, observer):
        try:
            self.observers.remove(observer)
        except ValueError:
            print('Failed to remove: {}'.format(observer))

    def notify(self):
        [o.notify(self) for o in self.observers]


class DefaultFormatter(Publisher):

    def __init__(self, name):
        Publisher.__init__(self)
        self.name = name
        self._data = 0

    def __str__(self):
        return "{}: '{}' has data = {}".format(type(self).__name__, self.name, self._data)

    @property
    def data(self):
        return self._data

    @data.setter
    def data(self, new_value):
        try:
            self._data = int(new_value)
        except ValueError as e:
            print('Error: {}'.format(e))
        else:
            self.notify()


class HexFormatter:

    def notify(self, publisher):
        print("{}: '{}' has now hex data = {}".format(type(self).__name__,
                                                      publisher.name, hex(publisher.data)))


class BinaryFormatter:

    def notify(self, publisher):
        print("{}: '{}' has now bin data = {}".format(type(self).__name__,
                                                      publisher.name, bin(publisher.data)))


def main():
    df = DefaultFormatter('test1')
    print(df)

    print()
    hf = HexFormatter()
    df.add(hf)
    df.data = 3
    print(df)

    print()
    bf = BinaryFormatter()
    df.add(bf)
    df.data = 21
    print(df)

    print()
    df.remove(hf)
    df.data = 40
    print(df)

    print()
    df.remove(hf)
    df.add(bf)
    df.data = 'hello'
    print(df)

    print()
    df.data = 15.8
    print(df)

if __name__ == '__main__':
    main()

 

1、發布者中有個方法添加所有觀察(訂閱)者對象,當發布某個東西(例子中的data變化)時,調用所有已添加的訂閱者的某個方法。

 

2、這個模式也是以一個十分重要的模式,java python里面的日志管理都是使用了觀察者模式。具體就是logger和handler就是發布者和訂閱者的關系,當logger添加了stremhandler,那么日志就可以顯示到控制台,添加了filehandler那么就可以記錄到文件,添加了smtphandler就可以把日志發送到郵箱。十分的方便解耦,可以選擇日志記錄到某一個地方或者幾個地方或者所有地方。如果日志想要記錄到mongo redis什么的,只需要繼承handler基類,自己實現emit方法就可以了,如果不理解這個關系,就很難自己寫日志擴展,或者是只能照葫蘆畫瓢,不知道為什么要那么寫,為什么添加了handler就可以把日志記錄到相關地方。如果使用print並且實現以上這些擴展那要寫很多東西,還不如使用日志。如果生產項目全部直接使用裸print,這樣寫代碼真的是很垃圾小學生水平,因為項目跑起來后,文件引用一環套一環根本不知道哪里print的,而且print要想擴展那又是成了自己發明logging模塊了。

 

3、再順便說下logging日志使用logger.debug 和logging.debug有什么區別?我從不使用logging.debug。包括所有三方包絕對都不會直接這么去使用。logging.debug的debug是一個函數,直接這么寫那么日志的命名空間是root根日志,如果想禁用這個日志,那么是removerhandler還是直接設置級別為critical來禁用日志?兩種都不好,對根日志操作打擊面積太大誤傷率太高,萬一有的地方的日志你就是想記錄呢。而且logging定制性不高,你想把某個日志記錄到a文件,某個日志記錄到b文件,某個日志只發郵件,就必須用更小命名空間的logger了。logging.debug實際是  logging.getLogger(None).debug(),   logger.debug是logging.getLogger(‘yourname’).debug(),一般yourname可以設置成__name__方便快捷,所以可以對單獨命名空間的日志進行定制handler或者移除handler或者對某類型日志設置最高級別。例如使用urllib時候,可以單獨的操縱connectionpool命名空間的日志,設置顯示他或者不顯示他,設置他的級別為error級別完全不會影響到別的命名空間下的日志的級別設置。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM