python 設計模式之訪問者模式

 寫在前面php

 設計模式是通過總結、優化的,對咱們常常會碰到的一些編程問題的可重用解決方案。一個設計模式並不像一個類或一個庫那樣可以直接做用於咱們的代碼。反之,設計模式更爲高級,它是一種必須在特定情形下實現的一種方法模板。設計模式不會綁定具體的編程語言。一個好的設計模式應該可以用大部分編程語言實現(若是作不到所有的話,具體取決於語言特性)。最爲重要的是,設計模式也是一把雙刃劍,若是設計模式被用在不恰當的情形下將會形成災難,進而帶來無窮的麻煩。然而若是設計模式在正確的時間被用在正確地地方,它將是你的救星。html

 

1。爲何要使用設計模式?

從理論上來講,設計模式是對程序問題比較好的解決方案。無數的程序員都曾經遇到過這些問題,而且他們使用這些解決方案去處理這些問題。因此當你遇到一樣的問題,爲何要去想着建立一個解決方案而不是用現成的而且被證實是有效的呢?python

 

2。訪問者模式解決了什麼問題?

1)對象結構中對象對應的類不多改變,但常常須要在此對象結構上定義新的操做。  
2)須要對一個對象結構中的對象進行不少不一樣的而且不相關的操做,而須要避免讓這些操做」污染」這些對象的類,也不但願在增長新操做時修改這些類。程序員

 

3。訪問者模式使用場景

1)對象結構比較穩定,但常常須要在此對象結構上定義新的操做編程

2)須要對一個對象結構中的對象進行不少不一樣的且不相關的操做,而須要避免這些操做「污染」這些對象的類,也不但願在增長新操做時修改這些類。設計模式

好比:訪問者能夠對功能進行統一,能夠作報表、UI、攔截器與過濾器。數據結構

 

數據類只提供一個數據處理的接口,而數據類的處理方法咱們叫它訪問者app

下面例子能夠實現:安排不一樣年份的財務報表給不一樣的角色分析,這就是訪問者模式的魅力;訪問者模式的核心是在保持原有數據結構的基礎上,實現多種數據的處理方法,該方法的角色就是訪問者。編程語言

 

4。訪問者模式優勢

1)使得數據結構和做用於結構上的操做解耦,使得操做集合能夠獨立變化。優化

2)添加新的操做或者說訪問者會很是容易。

3)將對各個元素的一組操做集中在一個訪問者類當中。

4)使得類層次結構不改變的狀況下,能夠針對各個層次作出不一樣的操做,而不影響類層次結構的完整性。

5)能夠跨越類層次結構,訪問不一樣層次的元素類,作出相應的操做。
6)若是操做的邏輯改變,咱們只須要改變訪問者的實現就夠了,而不用去修改其餘全部的商品類。

7)添加新類別的商品到系統變得容易。只須要改變一下訪問者接口以及其實現。已經存在的商品類別不會被幹擾影響。

 

5。訪問者模式缺點

1)增長新的元素會很是困難。

2)實現起來比較複雜,會增長系統的複雜性。

3)破壞封裝,若是將訪問行爲放在各個元素中,則能夠不暴露元素的內部結構和狀態,但使用訪問者模式的時候,爲了讓訪問者能獲取到所關心的信息,元素類不得不暴露出一些內部的狀態和結構,就像收入和支出類必須提供訪問金額和單子的項目的方法同樣。

4)visit()方法的返回值的類型在設計系統式就須要明確。否則,就須要修改訪問者的接口以及全部接口實現。另外若是訪問者接口的實現太多,系統的擴展性就會降低。

 

 6。舉個例子來訪問者模式

例子我也是拿了別人的,我作了一些小修改。變了些參數變量名。這個例子執行訪問的類 AnalyseData也能夠不要的。

#data   base class
class Finance:
    def __init__(self):
        self.salesvolume=None  #銷售額
        self.cost=None      #成本
        self.history_salesvolume=None   #歷史銷售額
        self.history_cost=None  #歷史成本

    def set_salesvolume(self,value):
        self.salesvolume=value

    def set_cost(self,value):
        self.cost=value

    def set_history_salesvolume(self,value):
        self.history_salesvolume=value

    def set_history_cost(self,value):
        self.history_cost=value

    def accept(self,visitor):
        pass


#2018年的財務狀況
class Finance_year(Finance):
    def __init__(self,year):
        Finance.__init__(self)
        self.analyst=[]
        self.year=year

    def add_analyst(self,worker):  #有哪些分析師來分析數據
        self.analyst.append(worker)

    def accept(self):   #分析師列表裏面的人去分析數據
        for v in self.analyst:
            v.visit(self)



#會計
class Accounting:
    def __init__(self):
        self.id='會計'
        self.Duty='計算報表'

    def visit(self,year_data):
        print('我如今分析的是{}年的數據'.format(year_data.year))
        print('個人身份是:{},職責:'.format(self.id,self.Duty))
        print('本年度純利潤:{}'.format(year_data.salesvolume-year_data.cost))
        print('---------------------------------------')

        
    
#財務總監
class Audit:
    def __init__(self):
        self.id='財務總監'
        self.Duty='分析業績'

    def visit(self,year_data):  #要把具體哪一年的數據傳給分析師,讓分析師去分析
        print('我如今分析的是{}年的數據'.format(year_data.year))
        print('個人身份是:{},職責:'.format(self.id,self.Duty))
        if year_data.salesvolume-year_data.cost > year_data.history_salesvolume - year_data.history_cost:
            msg='較同期上漲'
        else:
            msg='較同期下跌'
        print('本年度公司業績:{}'.format(msg))
        print('---------------------------------')

#戰略顧問
class Advisor:
    def __init__(self):
        self.id='戰略顧問'
        self.Duty='制定明年策略'
            
    def visit(self,year_data):
        print('我如今分析的是{}年的數據'.format(year_data.year))
        print('個人身份是:{},職責:'.format(self.id,self.Duty))
        if year_data.salesvolume > year_data.history_salesvolume:
            msg='行業上漲,擴大規模'
        else:
            msg='行業下跌,減小規模'
        print('本年度公司業績:{}'.format(msg))
        print('------------------------------')

#執行分析
class AnalyseData:
    def __init__(self):
        self.datalist=[]  #須要處理的數據列表,

            
    def add_data(self,year_data):
        self.datalist.append(year_data)

    def remove_data(self,year_data):
        self.datalist.remove(year_data)

    def visit(self):
        for d in self.datalist:
            d.accept()


if __name__=='__main__':
    w=AnalyseData() #計劃安排財務,總監,顧問對2018年數據處理
    finance_2018=Finance_year(2018)  #2018年的財務數據
    finance_2018.set_salesvolume(200)
    finance_2018.set_cost(90)
    finance_2018.set_history_salesvolume(190)
    finance_2018.set_history_cost(80)

    accounting=Accounting()
    audit=Audit()
    advisor=Advisor()

    finance_2018.add_analyst(accounting) #會計參與2018年的數據分析,而後執行了本身的visit方法
    finance_2018.add_analyst(audit)
    finance_2018.add_analyst(advisor)     
 

    #finance_2018.accept()   #也能夠直接這樣調用
    w.add_data(finance_2018)
    w.visit()

 

 

 

參考

https://yq.aliyun.com/articles/694041

https://www.cnblogs.com/xiaozhiqi/p/5778865.html

https://www.lmlphp.com/user/56/article/item/12041/

https://blog.csdn.net/a910626/article/details/50766033

相關文章
相關標籤/搜索