Java訪問(wèn)者設(shè)計(jì)模式詳細(xì)講解
編程是一門(mén)藝術(shù),大批量的改動(dòng)顯然是非常丑陋的做法,用心的琢磨寫(xiě)的代碼讓它變的更美觀。
在生活中,電影或電視劇中的人物角色,不同的觀眾對(duì)他們的評(píng)價(jià)也不同;還有顧客在商場(chǎng)購(gòu)物時(shí)放在“購(gòu)物車(chē)”中的商品,顧客主要關(guān)心所選商品的性價(jià)比,而收銀員關(guān)心的是商品的價(jià)格和數(shù)量。
這些被處理的數(shù)據(jù)元素相對(duì)穩(wěn)定而訪問(wèn)方式多種多樣的數(shù)據(jù)結(jié)構(gòu),如果用“訪問(wèn)者模式”來(lái)處理比較方便。訪問(wèn)者模式能把處理方法從數(shù)據(jù)結(jié)構(gòu)中分離出來(lái),并可以根據(jù)需要增加新的處理方法,且不用修改原來(lái)的程序代碼與數(shù)據(jù)結(jié)構(gòu),這提高了程序的擴(kuò)展性和靈活性。
1.模式的定義
訪問(wèn)者(Visitor)模式:是將作用于某種數(shù)據(jù)結(jié)構(gòu)中的各元素的操作分離出來(lái)封裝成獨(dú)立的類(lèi),使其在不改變數(shù)據(jù)結(jié)構(gòu)的前提下可以添加作用于這些元素的新的操作,為數(shù)據(jù)結(jié)構(gòu)中的每個(gè)元素提供多種訪問(wèn)方式。它將對(duì)數(shù)據(jù)的操作與數(shù)據(jù)結(jié)構(gòu)進(jìn)行分離,是行為類(lèi)模式中最復(fù)雜的一種模式。
訪問(wèn)者設(shè)計(jì)模式主要解決:java多態(tài)方法重載的靜態(tài)化問(wèn)題。
2.訪問(wèn)者設(shè)計(jì)模式的優(yōu)點(diǎn)與不足
訪問(wèn)者(Visitor)模式是一種對(duì)象行為型模式,其主要優(yōu)點(diǎn):
- 擴(kuò)展性好。能夠在不修改對(duì)象結(jié)構(gòu)中的元素的情況下,為對(duì)象結(jié)構(gòu)中的元素添加新的功能。
- 復(fù)用性好??梢酝ㄟ^(guò)訪問(wèn)者來(lái)定義整個(gè)對(duì)象結(jié)構(gòu)通用的功能,從而提高系統(tǒng)的復(fù)用程度。
- 靈活性好。訪問(wèn)者模式將數(shù)據(jù)結(jié)構(gòu)與作用于結(jié)構(gòu)上的操作解耦,使得操作集合可相對(duì)自由地演化而不影響系統(tǒng)的數(shù)據(jù)結(jié)構(gòu)。
- 符合單一職責(zé)原則。訪問(wèn)者模式把相關(guān)的行為封裝在一起,構(gòu)成一個(gè)訪問(wèn)者,使每一個(gè)訪問(wèn)者的功能都比較單一。
訪問(wèn)者(Visitor)模式的不足:
- 增加新的元素類(lèi)很困難。在訪問(wèn)者模式中,每增加一個(gè)新的元素類(lèi),都要在每一個(gè)具體訪問(wèn)者類(lèi)中增加相應(yīng)的具體操作,這違背了“開(kāi)閉原則”。
- 破壞封裝。訪問(wèn)者模式中具體元素對(duì)訪問(wèn)者公布細(xì)節(jié),這破壞了對(duì)象的封裝性。
- 違反了依賴倒置原則。訪問(wèn)者模式依賴了具體類(lèi),而沒(méi)有依賴抽象類(lèi)。
3.訪問(wèn)者設(shè)計(jì)模式的實(shí)現(xiàn)思路
訪問(wèn)者(Visitor)模式實(shí)現(xiàn)的關(guān)鍵是如何將作用于元素的操作分離出來(lái)封裝成獨(dú)立的類(lèi)
訪問(wèn)者模式包含以下主要角色。
- 抽象訪問(wèn)者(Visitor)角色:定義一個(gè)訪問(wèn)具體元素的接口,為每個(gè)具體元素類(lèi)對(duì)應(yīng)一個(gè)訪問(wèn)操作 visit() ,該操作中的參數(shù)類(lèi)型標(biāo)識(shí)了被訪問(wèn)的具體元素。
- 具體訪問(wèn)者(ConcreteVisitor)角色:實(shí)現(xiàn)抽象訪問(wèn)者角色中聲明的各個(gè)訪問(wèn)操作,確定訪問(wèn)者訪問(wèn)一個(gè)元素時(shí)該做什么。
- 抽象元素(Element)角色:聲明一個(gè)包含接受操作 accept() 的接口,被接受的訪問(wèn)者對(duì)象作為 accept() 方法的參數(shù)。
- 具體元素(ConcreteElement)角色:實(shí)現(xiàn)抽象元素角色提供的 accept() 操作,其方法體通常都是 visitor.visit(this) ,另外具體元素中可能還包含本身業(yè)務(wù)邏輯的相關(guān)操作。
- 對(duì)象結(jié)構(gòu)(Object Structure)角色:是一個(gè)包含元素角色的容器,提供讓訪問(wèn)者對(duì)象遍歷容器中的所有元素的方法,通常由 List、Set、Map 等聚合類(lèi)實(shí)現(xiàn)。
4.訪問(wèn)者設(shè)計(jì)模式實(shí)例
場(chǎng)景介紹:統(tǒng)計(jì)不同水果的價(jià)格,不同的水果放置到不同的集合,但是由于java多態(tài)中方法重載是靜態(tài)化的不足,導(dǎo)致統(tǒng)計(jì)不出來(lái)價(jià)格,就可以使用訪問(wèn)者設(shè)計(jì)模式來(lái)處理。
public interface Fruit { int price(); void draw(); int accept(Visit visit); } public class Apple implements Fruit { private int price = 100; public Apple(){ } public Apple(int price){ this.price = price; } public void pack(AppleBag bag){ bag.pack(); } @Override public int price() { return price; } @Override public void draw() { System.out.print("蘋(píng)果紅富士"); } public void setPrice(int price) { this.price = price; } public int accept(Visit visit){ /*指針可以傳遞真實(shí)類(lèi)型*/ return visit.sell(this); } } public class Banana implements Fruit { private int price = 60; @Override public int price() { return price; } public void pack(BananaBag bag){ bag.pack(); } @Override public void draw() { System.out.print("仙人蕉"); } public int accept(Visit visit){ return visit.sell(this); } public void setPrice(int price) { this.price = price; } } public class Orange implements Fruit { private String name = ""; private int price = 70; public Orange(String name,int price){ this.price = price; this.name = name; } public void pack(OrangeBag bag){ bag.pack(); } @Override public int price() { return price; } @Override public void draw() { System.out.print("砂糖桔"); } public int accept(Visit visit){ return visit.sell(this); } public void setPrice(int price) { this.price = price; } } public class Visit { /*蘋(píng)果計(jì)價(jià)*/ public int sell(Apple apple){ System.out.println("apple's price: ¥50"); return 50; } /*桔子計(jì)價(jià)*/ public int sell(Orange orange){ System.out.println("orange's price: ¥20"); return 20; } /*香蕉計(jì)價(jià)*/ public int sell(Banana banana){ System.out.println("banana's price: ¥30"); return 30; } //其它水果計(jì)價(jià) public int sell(Fruit fruit){ System.out.println("other price: ¥10"); return 10; } } public class VisitClient { private static Visit visit = new Visit(); /*庫(kù)存*/ private static List<Fruit> list = new ArrayList<>(); static { list.add(StaticFactory.getFruitApple()); list.add(StaticFactory.getFruitOrange()); list.add(StaticFactory.getFruitBanana()); list.add(StaticFactory.getFruitApple()); list.add(StaticFactory.getFruitOrange()); } private static int price() { int total = 0; for (Fruit fruit : list) { total += fruit.accept(visit); } System.out.println("總價(jià)值:" + total); return total; } public static void main(String[] args) { price(); }
訪問(wèn)者設(shè)計(jì)模式的關(guān)鍵是:不能直接使用visit對(duì)象直接調(diào)用sell方法將水果對(duì)象傳遞進(jìn)去,因?yàn)橹苯觽鬟f進(jìn)去由于方法重載的靜態(tài)化問(wèn)題,不會(huì)執(zhí)行相應(yīng)的方法,需要是使用fruit的accept方法才行。
5.訪問(wèn)者設(shè)計(jì)模式的使用場(chǎng)景
通常在以下情況可以考慮使用訪問(wèn)者(Visitor)模式。
- 對(duì)象結(jié)構(gòu)相對(duì)穩(wěn)定,但其操作算法經(jīng)常變化的程序。
- 對(duì)象結(jié)構(gòu)中的對(duì)象需要提供多種不同且不相關(guān)的操作,而且要避免讓這些操作的變化影響對(duì)象的結(jié)構(gòu)。
- 對(duì)象結(jié)構(gòu)包含很多類(lèi)型的對(duì)象,希望對(duì)這些對(duì)象實(shí)施一些依賴于其具體類(lèi)型的操作。
到此這篇關(guān)于Java訪問(wèn)者設(shè)計(jì)模式詳細(xì)講解的文章就介紹到這了,更多相關(guān)Java訪問(wèn)者模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java設(shè)計(jì)模式之訪問(wèn)者模式
- 深入理解Java設(shè)計(jì)模式之訪問(wèn)者模式
- Java設(shè)計(jì)模式之java訪問(wèn)者模式詳解
- 23種設(shè)計(jì)模式(16)java訪問(wèn)者模式
- Java設(shè)計(jì)模式之訪問(wèn)者模式使用場(chǎng)景及代碼示例
- JAVA設(shè)計(jì)模式之訪問(wèn)者模式原理與用法詳解
- 舉例講解設(shè)計(jì)模式中的訪問(wèn)者模式在Java編程中的運(yùn)用
- 詳解Java設(shè)計(jì)模式編程中的訪問(wèn)者模式
- JAVA設(shè)計(jì)模式之訪問(wèn)者模式詳解
相關(guān)文章
詳解Spring Security如何在權(quán)限中使用通配符
小伙伴們知道,在Shiro中,默認(rèn)是支持權(quán)限通配符的?,F(xiàn)在給用戶授權(quán)的時(shí)候,可以一個(gè)權(quán)限一個(gè)權(quán)限的配置,也可以直接用通配符。本文將介紹Spring Security如何在權(quán)限中使用通配符,需要的可以參考一下2022-06-06Spring Boot 結(jié)合 aop 實(shí)現(xiàn)讀寫(xiě)分離
這篇文章主要介紹了Spring Boot 結(jié)合 aop 實(shí)現(xiàn)讀寫(xiě)分離的示例,幫助大家更好的理解和使用Spring Boot框架,感興趣的朋友可以了解下2020-11-11SpringBoot集成screw實(shí)現(xiàn)數(shù)據(jù)庫(kù)文檔生成的代碼示例
數(shù)據(jù)庫(kù)設(shè)計(jì)文檔是項(xiàng)目技術(shù)文檔的重要組成部分,Screw 是一款開(kāi)源的數(shù)據(jù)庫(kù)文檔生成工具,它支持多種數(shù)據(jù)庫(kù)類(lèi)型,并能生成豐富格式的文檔,本文將通過(guò)一個(gè)實(shí)際的例子,展示如何使用 Spring Boot 集成 Screw 生成數(shù)據(jù)庫(kù)設(shè)計(jì)文檔2024-07-07SpringBoot使用@Value實(shí)現(xiàn)給靜態(tài)變量注入值
這篇文章主要介紹了SpringBoot使用@Value實(shí)現(xiàn)給靜態(tài)變量注入值的方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07IDEA+Maven創(chuàng)建Spring項(xiàng)目的實(shí)現(xiàn)步驟
這篇文章主要介紹了IDEA+Maven創(chuàng)建Spring項(xiàng)目的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07Java多線程和并發(fā)基礎(chǔ)面試題(問(wèn)答形式)
多線程和并發(fā)問(wèn)題是Java技術(shù)面試中面試官比較喜歡問(wèn)的問(wèn)題之一。在這里,從面試的角度列出了大部分重要的問(wèn)題,感興趣的小伙伴們可以參考一下2016-06-06