Java訪問者設計模式詳細講解
編程是一門藝術,大批量的改動顯然是非常丑陋的做法,用心的琢磨寫的代碼讓它變的更美觀。
在生活中,電影或電視劇中的人物角色,不同的觀眾對他們的評價也不同;還有顧客在商場購物時放在“購物車”中的商品,顧客主要關心所選商品的性價比,而收銀員關心的是商品的價格和數(shù)量。
這些被處理的數(shù)據(jù)元素相對穩(wěn)定而訪問方式多種多樣的數(shù)據(jù)結構,如果用“訪問者模式”來處理比較方便。訪問者模式能把處理方法從數(shù)據(jù)結構中分離出來,并可以根據(jù)需要增加新的處理方法,且不用修改原來的程序代碼與數(shù)據(jù)結構,這提高了程序的擴展性和靈活性。
1.模式的定義
訪問者(Visitor)模式:是將作用于某種數(shù)據(jù)結構中的各元素的操作分離出來封裝成獨立的類,使其在不改變數(shù)據(jù)結構的前提下可以添加作用于這些元素的新的操作,為數(shù)據(jù)結構中的每個元素提供多種訪問方式。它將對數(shù)據(jù)的操作與數(shù)據(jù)結構進行分離,是行為類模式中最復雜的一種模式。
訪問者設計模式主要解決:java多態(tài)方法重載的靜態(tài)化問題。
2.訪問者設計模式的優(yōu)點與不足
訪問者(Visitor)模式是一種對象行為型模式,其主要優(yōu)點:
- 擴展性好。能夠在不修改對象結構中的元素的情況下,為對象結構中的元素添加新的功能。
- 復用性好??梢酝ㄟ^訪問者來定義整個對象結構通用的功能,從而提高系統(tǒng)的復用程度。
- 靈活性好。訪問者模式將數(shù)據(jù)結構與作用于結構上的操作解耦,使得操作集合可相對自由地演化而不影響系統(tǒng)的數(shù)據(jù)結構。
- 符合單一職責原則。訪問者模式把相關的行為封裝在一起,構成一個訪問者,使每一個訪問者的功能都比較單一。
訪問者(Visitor)模式的不足:
- 增加新的元素類很困難。在訪問者模式中,每增加一個新的元素類,都要在每一個具體訪問者類中增加相應的具體操作,這違背了“開閉原則”。
- 破壞封裝。訪問者模式中具體元素對訪問者公布細節(jié),這破壞了對象的封裝性。
- 違反了依賴倒置原則。訪問者模式依賴了具體類,而沒有依賴抽象類。
3.訪問者設計模式的實現(xiàn)思路
訪問者(Visitor)模式實現(xiàn)的關鍵是如何將作用于元素的操作分離出來封裝成獨立的類
訪問者模式包含以下主要角色。
- 抽象訪問者(Visitor)角色:定義一個訪問具體元素的接口,為每個具體元素類對應一個訪問操作 visit() ,該操作中的參數(shù)類型標識了被訪問的具體元素。
- 具體訪問者(ConcreteVisitor)角色:實現(xiàn)抽象訪問者角色中聲明的各個訪問操作,確定訪問者訪問一個元素時該做什么。
- 抽象元素(Element)角色:聲明一個包含接受操作 accept() 的接口,被接受的訪問者對象作為 accept() 方法的參數(shù)。
- 具體元素(ConcreteElement)角色:實現(xiàn)抽象元素角色提供的 accept() 操作,其方法體通常都是 visitor.visit(this) ,另外具體元素中可能還包含本身業(yè)務邏輯的相關操作。
- 對象結構(Object Structure)角色:是一個包含元素角色的容器,提供讓訪問者對象遍歷容器中的所有元素的方法,通常由 List、Set、Map 等聚合類實現(xiàn)。
4.訪問者設計模式實例
場景介紹:統(tǒng)計不同水果的價格,不同的水果放置到不同的集合,但是由于java多態(tài)中方法重載是靜態(tài)化的不足,導致統(tǒng)計不出來價格,就可以使用訪問者設計模式來處理。
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){
/*指針可以傳遞真實類型*/
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 {
/*蘋果計價*/
public int sell(Apple apple){
System.out.println("apple's price: ¥50");
return 50;
}
/*桔子計價*/
public int sell(Orange orange){
System.out.println("orange's price: ¥20");
return 20;
}
/*香蕉計價*/
public int sell(Banana banana){
System.out.println("banana's price: ¥30");
return 30;
}
//其它水果計價
public int sell(Fruit fruit){
System.out.println("other price: ¥10");
return 10;
}
}
public class VisitClient {
private static Visit visit = new Visit();
/*庫存*/
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("總價值:" + total);
return total;
}
public static void main(String[] args) {
price();
}
訪問者設計模式的關鍵是:不能直接使用visit對象直接調用sell方法將水果對象傳遞進去,因為直接傳遞進去由于方法重載的靜態(tài)化問題,不會執(zhí)行相應的方法,需要是使用fruit的accept方法才行。
5.訪問者設計模式的使用場景
通常在以下情況可以考慮使用訪問者(Visitor)模式。
- 對象結構相對穩(wěn)定,但其操作算法經(jīng)常變化的程序。
- 對象結構中的對象需要提供多種不同且不相關的操作,而且要避免讓這些操作的變化影響對象的結構。
- 對象結構包含很多類型的對象,希望對這些對象實施一些依賴于其具體類型的操作。
到此這篇關于Java訪問者設計模式詳細講解的文章就介紹到這了,更多相關Java訪問者模式內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
HttpServletRequestWrapper干預Request處理流程解析
這篇文章主要分析在?Tomcat的處理?http?請求的流程中干預?Request對象,?通過基于HttpServletRequestWrapper和?Filter組合進行干預,有需要的朋友可以借鑒參考下,希望能夠有所幫助2023-09-09
淺析Java中Apache BeanUtils和Spring BeanUtils的用法
這篇文章主要介紹了Java中Apache BeanUtils和Spring BeanUtils的用法,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-11-11
kotlin快速入門之標準函數(shù)與靜態(tài)方法
學完了Kotlin的基礎知識,是時候來來學習 Kotlin的標準函數(shù)和靜態(tài)方法了,下面這篇文章主要給大家介紹了關于kotlin快速入門之標準函數(shù)與靜態(tài)方法的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下2021-09-09

