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

