日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

旧访客设计模式的新生活

發布時間:2023/12/3 asp.net 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 旧访客设计模式的新生活 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

介紹

訪客 [1、2]是眾所周知的經典設計模式。 有很多資源對其進行了詳細說明。 在不深入研究實現的情況下,我將簡要提醒一下該模式的概念,解釋其優點和缺點,并提出一些可以使用Java編程語言輕松應用于其的改進。

古典游客

[Visitor] 允許在運行時將一個或多個操作應用于一組對象,從而將操作與對象結構分離。

(四人幫)

該模式基于通常稱為的接口。 Visitable具有由模型類和一組來實現Visitors實現為每個相關的模型類方法(算法)。

public interface Visitable { public void accept(Visitor visitor); } public class Book implements Visitable { ....... @Override public void accept(Visitor visitor) {visitor.visit( this )}; ....... } public class Cd implements Visitable { ....... @Override public void accept(Visitor visitor) {visitor.visit( this )}; ....... } Visitor { interface Visitor { public void visit(Book book); public void visit(Magazine magazine); public void visit(Cd cd); }

現在我們可以實現各種visitors ,例如

  • PrintVisitor是提供打印Visitable
  • DbVisitor其存儲在數據庫中的DbVisitor ,
  • 將其添加到購物車的ShoppingCart

等等

訪客模式的缺點

  • visit()方法的返回類型必須在設計時定義。 實際上,在大多數情況下,這些方法是void 。
  • accept()方法的實現在所有類中都是相同的。 顯然,我們更喜歡避免代碼重復。
  • 每次添加新的模型類時,每個visitor必須更新,因此維護變得很困難。
  • 對于某些visitor ,某些模型類不可能有可選的實現。 例如,可以通過電子郵件將軟件發送給買方,而不能發送牛奶。 但是,兩者都可以使用傳統的郵寄方式遞送。 因此, EmailSendingVisitor不能實現方法visit(Milk)但可以實現visit(Software) 。 可能的解決方案是引發UnsupportedOperationException但調用者無法提前知道在調用該方法之前將引發此異常。
  • 經典訪客模式的改進

    返回值

    首先,讓我們將返回值添加到Visitor接口。 通用定義可以使用泛型來完成。

    public interface Visitable { public <R> R accept(Visitor<R> visitor); } interface Visitor<R> { public R visit(Book book); public R visit(Magazine magazine); public R visit(Cd cd); }

    好吧,這很容易。 現在,我們可以將任何能帶來價值的Visitor應用于我們的圖書。 例如, DbVisitor可能返回DB(整數)中已更改記錄的數量,而ToJson訪問者可能會將我們對象的JSON表示形式返回為String。 (該示例可能不太有機,在現實生活中,我們通常使用其他技術將對象序列化為JSON,但是就其在理論上可以使用Visitor模式而言,已經足夠了)。

    默認實現

    接下來,讓我們感謝Java 8在接口內保留默認實現的能力:

    public interface Visitable<R> { default R accept(Visitor<R> visitor) { return visitor.visit( this ); } }

    現在,實現Visitable類本身不必實現>visit() :在大多數情況下,默認實現就足夠了。

    上面建議的改進解決了缺點#1和#2。

    單訪客

    讓我們嘗試應用進一步的改進。 首先,讓我們定義接口MonoVisitor如下:

    public interface MonoVisitor<T, R> { R visit(T t); }

    Visitor名稱已更改為MonoVisitor以避免名稱沖突和可能的混淆。 通過這本書, visitor定義了許多重載方法visit() 。 他們每個人都為每個Visitable接受不同類型的參數。 因此,根據定義, Visitor不能是通用的。 必須在項目級別上定義和維護它。 MonoVisitor僅定義一種方法。 類型安全由泛型保證。 即使使用不同的通用參數,單個類也無法多次實現相同的接口。 這意味著即使將MonoVisitor多個實現分為一組,我們也必須保留它們。

    功能參考,而不是訪客

    由于MonoVisitor只有一種業務方法,因此我們必須為每個模型類創建實現。 但是,我們不想創建單獨的頂級類,而是希望將它們分組為一個類。 這個新的visitor在各種Visitable類與java.util.Function實現之間持有Map,并將visit()方法的調用分派給特定的實現。

    因此,讓我們看一下MapVisitor。

    public class MapVisitor<R> implements Function<Class<? extends Visitable>, MonoVisitor<? extends Visitable, R>> { private final Map<Class<? extends Visitable>, MonoVisitor<? extends Visitable, R>> visitors; MapVisitor(Map<Class<? extends Visitable>, MonoVisitor<? extends Visitable, R>> visitors) { this .visitors = visitors; } @Override public MonoVisitor apply(Class clazz) { return visitors.get(clazz); } }

    MapVisitor

    • 實現Function

      為了檢索特定的實現(為便于閱讀,此處省略了完整的泛型;有關詳細定義,請查看代碼段)

    • 接收映射中類和實現之間的映射
    • 檢索適合給定類的特定實現

    MapVisitor具有程序包專用的構造函數。 使用特殊構建器完成的MapVisitor初始化非常簡單且靈活:

    MapVisitor<Void> printVisitor = MapVisitor.builder(Void. class ) .with(Book. class , book -> {System.out.println(book.getTitle()); return null ;}) .with(Magazine. class , magazine -> {System.out.println(magazine.getName()); return null ;}) .build();

    MapVisitor的用法類似于傳統的Visitor :

    someBook.accept(printVisitor); someMagazine.accept(printVisitor);

    我們的MapVisitor還有一個好處。 必須實現在傳統訪問者的接口中聲明的所有方法。 但是,通常無法實現某些方法。

    例如,我們想要實現演示動物可以執行的各種動作的應用程序。 用戶可以選擇一種動物,然后通過從菜單中選擇特定的動作來使它做某事。

    這是動物名單: Duck, Penguin, Wale, Ostrich 這是動作列表: Walk, Fly, Swim. 我們決定按操作設置訪問者: WalkVisitor, FlyVisitor, SwimVisitor 。 鴨子可以做所有三個動作,企鵝不能飛,瓦爾只能游泳, 鴕鳥只能行走。 因此,如果用戶試圖使Wale走路或Ostrich飛行,我們決定拋出異常。 但是這種行為不是用戶友好的。 確實,用戶只有在按下操作按鈕時才會收到錯誤消息。 我們可能更希望禁用不相關的按鈕。 MapVisitor允許此操作而無需其他數據結構或代碼重復。 我們甚至不必定義new或擴展任何其他接口。 相反,我們更喜歡使用標準接口java.util.Predicate :

    public class MapVisitor<R> implements Function<Class<? extends Visitable>, MonoVisitor<? extends Visitable, R>>, Predicate<Class<? extends Visitable>> { private final Map<Class<? extends Visitable>, MonoVisitor<? extends Visitable, R>> visitors; ............... @Override public boolean test(Class<? extends Visitable> clazz) { return visitors.containsKey(clazz); } }

    現在我們可以調用函數test()來定義是否必須啟用或顯示選定動物的操作按鈕。

    github上提供了此處使用的示例的完整源代碼。

    結論

    本文演示了一些改進,這些改進使舊的Visitor模式變得更加靈活和強大。 建議的實現方式避免了實現經典的Vistor模式所需的某些樣板代碼。 以下是上述改進的簡要清單。

  • 這里描述的Visitor visit()方法可以返回值,因此可以實現為純函數[3],該函數有助于將Visitor模式與功能編程范例結合起來。
  • 將整體Visitor接口拆分為單獨的塊可以使其更加靈活,并簡化了代碼維護。
  • 可以在運行時使用構建器來配置MapVisitor ,因此它可能會更改其行為,具體取決于僅在運行時已知且在開發過程中不可用的信息。
  • 具有不同返回類型的訪問者可以應用于相同的Visitable類。
  • 在接口中完成的方法的默認實現會刪除許多典型的Visitor實現常用的樣板代碼。
  • 參考文獻

  • 維基百科
  • 區域
  • 純函數的定義 。
  • 翻譯自: https://www.javacodegeeks.com/2019/03/new-life-old-visitor-design-pattern.html

    總結

    以上是生活随笔為你收集整理的旧访客设计模式的新生活的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。