欧美色欧美亚洲高清在线视频-欧美色碰碰碰免费观看长视频-欧美色频-欧美色视频超清在线观看-国产精品免费看久久久-国产精品免费看久久久久

手機版 | 網站導航
觀察家網 > 宏觀 >

淺析訪問者模式

博客園 | 2023-07-31 05:39:57
0. 前言

在閱讀 Kubernetes: kubectl源碼時看到有關訪問者設計模式的運用。訪問者模式是行為型設計模式的一種,本篇文章將對訪問者模式做一個介紹。

1. 訪問者模式1.1 示例

首先,給出一個比較粗糙的示例。

實現程序,功能如下:


(相關資料圖)

當男人成功時,顯示我有一個好老婆;當女人成功時,顯示我有一個有愛的丈夫;當男人開心時,顯示我有一個玩具;當女人開心時,顯示我有一個有愛的丈夫;當男人傷心時,顯示我丟了玩具;當女人傷心時,顯示我丟了有愛的丈夫;

基于上述描述,實現示例代碼:

type man struct {action string}type woman struct {action string}func (m *man) status() {if m.action == "happy" {fmt.Println("I have a toy")}if m.action == "sad" {fmt.Println("I lost my toy")}if m.action == "success" {fmt.Println("I have a great wife")}}func (w *woman) status() {if w.action == "happy" {fmt.Println("I have a lovely husband")}if w.action == "sad" {fmt.Println("I lost my lovely husband")}if w.action == "success" {fmt.Println("I have a lovely husband")}}func main() {m := man{action: "sad",}m.status()}

示例代碼實現了想要的功能。可以看出,男人和女人類都具有 action且行為不一樣。

那么,如果增加 action,比如當男人戀愛時,顯示我終于脫單了;當女人戀愛時,顯示終于有人愛我了;就需要更新男人和女人類的 status方法,這不符合開閉原則。

1.2 解耦對象和行為

既然不符合開閉原則,那怎么樣才能解耦對象和行為,使得行為的變化不會影響到對象實現呢?

進一步看上述實現,男人和女人類是行為的主體,行為有成功時的行為,開心時的行為,傷心時的行為...

既然是解耦,那先把行為拿出來作為接口,在以具體的行為類實現接口。看看怎么把行為類和對象類分開。

實現代碼:

type status interface {manStatus()womanStatus()}type happy struct{}type sad struct{}type success struct{}func (h *happy) manStatus() {fmt.Println("I have a toy")}func (s *sad) manStatus() {fmt.Println("I lost my toy")}func (s *success) manStatus() {fmt.Println("I have a great wife")}func (h *happy) womanStatus() {fmt.Println("I have a lovely husband")}func (s *sad) womanStatus() {fmt.Println("I lost my lovely husband")}func (s *success) womanStatus() {fmt.Println("I have a lovely husband")}type man struct {}type woman struct {}

這里把對象類的 action屬性拿掉,相應的把 action轉換為行為類。行為類實現了接口,其中定義了 manStatus()womanStatus()方法。

這樣我們拆成了兩個類,對象類和行為類。怎么把這兩個類聯系起來呢?看代碼,男人類和男人類的行為,女人類和女人類的行為是有聯系的,初始化對象類和行為類:

m := man{}s := sad{}// m.demo(s)

應該通過 demo將對象和行為類聯系起來,然后調用 smanStatus()方法完成關聯:

func (m *man) accept(s status) {s.manStatus()}func (w *woman) accept(s status) {s.womanStatus()}func main() {m := &man{}s := &sad{}m.accept(s)}

demo重命名為 accept作為對象類的方法,在其中調用行為類的方法。

1.3 訪問者模式

至此,我們已經實現了訪問者模式。有人可能會問了,我怎么還是沒看出來?我們在分析上述代碼。

有兩個類,對象類和行為類。對象類實現 accept方法,其是動作的主體,將對象類和行為類關聯起來。行為類根據不同對象實現行為方法,其是行為的主體,行為是建立在對象之上的。

基于上述分析,我們繼續改造代碼:

type visitor interface {manStatus()womanStatus()}type happyVisitor struct{}type sadVisitor struct{}type successVisitor struct{}func (h *happyVisitor) manStatus() {fmt.Println("I have a toy")}func (s *sadVisitor) manStatus() {fmt.Println("I lost my toy")}func (s *successVisitor) manStatus() {fmt.Println("I have a great wife")}func (h *happyVisitor) womanStatus() {fmt.Println("I have a lovely husband")}func (s *sadVisitor) womanStatus() {fmt.Println("I lost my lovely husband")}func (s *successVisitor) womanStatus() {fmt.Println("I have a lovely husband")}type man struct {}type woman struct {}func (m *man) accept(s visitor) {s.manStatus()}func (w *woman) accept(s visitor) {s.womanStatus()}

結構基本沒變,只是重命名了一下,更容易分清主體。

上述示例對于行為類相比于對象類是主的體驗還不明顯,重新改寫代碼:

type visitor interface {manStatus(*man)womanStatus(*woman)}type happyVisitor struct{}type sadVisitor struct{}type successVisitor struct{}func (h *happyVisitor) manStatus(m *man) {fmt.Println(m.name, "I have a toy")}func (s *sadVisitor) manStatus(m *man) {fmt.Println(m.name, "I lost my toy")}func (s *successVisitor) manStatus(m *man) {fmt.Println(m.name, "I have a great wife")}type man struct {name string}func (m *man) accept(s visitor) {s.manStatus(m)}func main() {m := &man{"hxia"}s := &sadVisitor{}m.accept(s)}

改寫后的代碼,行為類會訪問對象類的 name屬性,對于行為類來說,對象類就是數據,是屬性。

基于此,畫出訪問者設計模式的 UML 圖:

訪問者模式在 GoF 合著的《設計模式:可復用面向對象軟件的基礎》中的定義是:

允許一個或多個操作應用到一組對象上,解耦操作和對象本身Allows for one or more operation to be applied to a set of objects at runtime, decoupling the operations from the object structure
2. VisitorFunc 和訪問者模式

前面介紹了訪問者模式,從定義看訪問者模式通過將一個或多個操作應用到一組對象上,以實現對象和操作的解耦。這里需要重點關注的點是一組對象。

一組意味著對象具有相似性,且結構是穩定的。試想如果男人和女人類中,女人沒有傷心時的行為,那就沒辦法將其歸為一組對象,或者需要實現 fake 傷心以保持對象的相似性。

既然定義的是一組,當然對象也可以是一個。假定對象是一個,使用函數 Visitor改寫上述訪問者模式代碼:

type VisitorFunc func(man)func happyVisitor(m man) {fmt.Println(m.name, "I have a good thing")}func sadVisitor(m man) {fmt.Println(m.name, "I have a bad thing")}func successVisitor(m man) {fmt.Println(m.name, "I finish a thing")}type man struct {name string}func (m man) accept(v VisitorFunc) {v(m)}func main() {m := man{"hxia"}m.accept(sadVisitor)}

這么改寫在于簡單,去掉類取而代之的是函數,用函數實現了具體的 Visitor。當然,這樣的 Visitor只能處理一種操作。

類似地,如果一組對象的行為是一樣的,也可以用函數 Visitor來實現:

type VisitorFunc func(person)func happyVisitor(p person) {fmt.Println(p.getName(), "I have a good thing")}func sadVisitor(p person) {fmt.Println(p.getName(), "I have a bad thing")}func successVisitor(p person) {fmt.Println(p.getName(), "I finish a thing")}type person interface {getName() string}type man struct {name string}type woman struct {name string}func (m man) getName() string {return m.name}func (w woman) getName() string {return w.name}func (m *man) accept(v VisitorFunc) {v(m)}func (w *woman) accept(v VisitorFunc) {v(w)}func main() {m := &man{"hxia"}m.accept(sadVisitor)}
2.1 嵌套 Visitor

如果操作作用于一個對象,可以用函數 Visitor來簡化實現。如果多個操作嵌套的作用于對象上,那么可以使用嵌套 Visitor實現,其效果類似于多個小應用訪問數據庫以實現某個功能。

代碼示例如下:

type VisitorFunc func(*man) errorfunc happyVisitor(m *man) error {fmt.Println(m.name)return nil}func sadVisitor(m *man) error {fmt.Println(m.age)return nil}func successVisitor(m *man) error {fmt.Println(m.sex)return nil}func validationFunc(m *man) error {if m.name == "" {return errors.New("empty name")}return nil}type man struct {name stringage  intsex  string}type Visitor interface {Visit(VisitorFunc) error}func (m *man) Visit(fn VisitorFunc) error {fmt.Println("in man")if err := fn(m); err != nil {return err}fmt.Println("out man")return nil}type validationVisitor struct {visitor Visitor}func (v validationVisitor) Visit(fn VisitorFunc) error {return v.visitor.Visit(func(m *man) error {fmt.Println("in validation")if m.name == "" {return errors.New("empty name")}if err := fn(m); err != nil {return err}fmt.Println("out validation")return nil})}type errorVisitor struct {visitor Visitor}func (v errorVisitor) Visit(fn VisitorFunc) error {return v.visitor.Visit(func(m *man) error {fmt.Println("in error")if err := fn(m); err != nil {return err}fmt.Println("out error")return nil})}type ageVisitor struct {visitor Visitor}func (v ageVisitor) Visit(fn VisitorFunc) error {return v.visitor.Visit(func(m *man) error {fmt.Println("in age")if err := fn(m); err != nil {return err}fmt.Println(m.name, m.age)fmt.Println("out age")return nil})}type VisitorList []Visitorfunc (l VisitorList) Visit(fn VisitorFunc) error {for i := range l {if err := l[i].Visit(fn); err != nil {return err}}return nil}func main() {var visitor Visitorm1 := &man{name: "hxia", age: 18}m2 := &man{name: "huyun", age: 29}m3 := &man{name: "troy", age: 25}visitors := []Visitor{m1, m2, m3}visitor = VisitorList(visitors)visitor = validationVisitor{visitor: visitor}visitor = errorVisitor{visitor: visitor}visitor = ageVisitor{visitor: visitor}visitor.Visit(happyVisitor)}

代碼有點長,其基本是 Kubernetes:kubectl訪問者模式的主體,把它看懂了,再去看 kubectl的訪問者模式實現就不難了。

首先,對象實現了 Visitor(類似于上例的 accept),接受函數 Visitor,函數 Visitor訪問對象操作:

func (m *man) Visit(fn VisitorFunc) error {...}

接著,將多個對象裝入 VisitorList,且該 VisitorList也實現了 Visitor接口方法。這么做是為了遍歷訪問每個對象:

func (l VisitorList) Visit(fn VisitorFunc) error {for i := range l {if err := l[i].Visit(fn); err != nil {return err}}return nil}

然后,是在函數 Visitor操作對象之后對對象做一些其它操作,這里定義了 validationVisitor用來驗證對象的名字是否為空:

func (v validationVisitor) Visit(fn VisitorFunc) error {...}// mainvisitor = validationVisitor{visitor: visitor}visitor.Visit(happyVisitor)

通過層層嵌套 Visitor實現對象的嵌套操作。

這些代碼了解了,再去看 Kubernetes:kubectl應該不難了,代碼在 這里。

3. 總結

優點

訪問者模式適用于對象復雜且具有較多操作的場景,使用訪問者模式可解耦對象和操作,簡化對象職責。訪問者模式側重在訪問者,對于訪問者而言,多加幾個訪問者操作不影響對象的實現,符合開閉原則。

缺點

由于訪問者模式解耦了對象和它的操作,對象的屬性暴露給訪問者,打破了對象和操作的封裝。訪問者模式對對象不友好,如果對象結構不穩定,很難使用訪問者模式。同時,如果要加入新對象,需要訪問者接口,實現和對象都要改,不符合開閉原則。4. 參考文章

訪問者模式GO 編程模式:K8S VISITOR 模式

標簽:

  • 標簽:中國觀察家網,商業門戶網站,新聞,專題,財經,新媒體,焦點,排行,教育,熱點,行業,消費,互聯網,科技,國際,文化,時事,社會,國內,健康,產業資訊,房產,體育。

相關推薦

主站蜘蛛池模板: 国产2021久久精品 | 日韩中文字幕在线观看 | 国产伦精品一区三区视频 | 国内精品久久久久久影院老狼 | 国产成人精品免费视频 | 久久国产免费观看精品 | 窝窝视频成人影院午夜在线 | www.网站黄网站 | 欧美在线小视频 | 天天摸夜夜摸成人免费视频 | 成人免费视频视频在线不卡 | 精品视频一区二区三区在线观看 | 免费观看成人www精品视频在线 | 特黄特a级特别特级特毛片 特黄特黄aaaa级毛片免费看 | 欧美一区在线观看视频 | 黄色的视频免费 | 欧美videosex极品hd | 日韩精品视频美在线精品视频 | 1级黄色录像 | 美女黄色免费在线观看 | 老子影院午夜伦不卡亚洲 | 国产成人小视频 | 国产成人深夜福利短视频99 | 欧美一区永久视频免费观看 | 欧美日韩加勒比一区二区三区 | 免费成人看片 | 天天看天天爽天天摸天天添 | 欧美一级看片a免费观看 | 国产一级毛片网站 | 中文字幕巨乱亚洲 | 日本欧美色图 | 亚洲国产成人久久一区二区三区 | 日本黄色的视频 | 欧美一级高清片免费一级 | 青青成人福利国产在线视频 | 日韩精品在线观看视频 | 视频福利一区 | 制服丝袜中文在线 | 国产精品乱| 97夜夜澡人人爽人人喊中国片 | 国产欧美在线播放 |