設計模式之訪問者模式

定義

封裝一些作用于某種數(shù)據(jù)結(jié)構(gòu)中的各元素的操作,它可以在不改變這個數(shù)據(jù)結(jié)構(gòu)的前提下定義作用于這些元素的新的操作。

Android 中源碼使用訪問者模式

ElementVisitor

特點

  • 優(yōu)點
    (1)各角色職責分離,符合單一職責原則。
    (2)具有優(yōu)秀的擴展性。
    (3)使得數(shù)據(jù)結(jié)構(gòu)和作用于結(jié)構(gòu)上的操作解耦,使得操作集合可以獨立變化。
    (4)靈活性。

  • 缺點
    (1)具體元素對訪問者公布細節(jié),違反了迪米特原則。
    (2)具體元素變更時導致修改成本大。
    (3)違反了依賴倒置原則,為了達到“區(qū)別對待”而依賴了具體類,沒有依賴抽象。

使用場景

(1)對象結(jié)構(gòu)比較穩(wěn)定,但經(jīng)常需要在此對象結(jié)構(gòu)上定義新的操作。
(2)需要對一個對象結(jié)構(gòu)中的對象進行很多不同的且不相關的操作,而需要避免這些操作“污染”這些對象的類,也不希望在增加新操作時修改這些類。

簡單實現(xiàn)

  1. 員工類
/**
 * Created on 2019/4/12 14:33
 *
 * @author Scarf
 */
public abstract class Staff {
    public String name;

    public int KPI;

    public Staff(String name) {
        this.name = name;
        this.KPI = new Random().nextInt(10);
    }

    public abstract void accept(Visitor visitor);
}

------------------------------------
/**
 * Created on 2019/4/12 14:37
 *
 * @author Scarf 
 */
public class Engineer extends Staff {
    private int codeLines;
    public Engineer(String name) {
        super(name);
        codeLines = new Random().nextInt(10 * 10000);
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    public int getCodeLines() {
        return codeLines;
    }
}

------------------------------------
/**
 * Created on 2019/4/12 14:39
 *
 * @author Scarf 
 */
public class Manager extends Staff {
    private int products;
    public Manager(String name) {
        super(name);
        products = new Random().nextInt(10);
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    public int getProducts() {
        return products;
    }
}
  1. 訪問接口
/**
 * Created on 2019/4/12 14:35
 *
 * @author Scarf 
 */
public interface Visitor {
    void visit(Engineer engineer);

    void visit(Manager manager);
}

--------------------------------
/**
 * Created on 2019/4/12 14:42
 *
 * @author Scarf 
 */
public class CEOVisitor implements Visitor {
    @Override
    public void visit(Engineer engineer) {
        Log.d("TAG",  engineer.name + ",KPI: "+ engineer.KPI  );
    }

    @Override
    public void visit(Manager manager) {
        Log.d("TAG", "產(chǎn)品經(jīng)理: " + manager.name + ",KPI:"+ manager.KPI +",產(chǎn)品數(shù)量: "+ manager.getProducts());
    }
}

--------------------------------
/**
 * Created on 2019/4/12 14:42
 *
 * @author Scarf
 */
public class CTOVisitor implements Visitor {
    @Override
    public void visit(Engineer engineer) {
        Log.d("TAG",  engineer.name + ",代碼數(shù)量: "+ engineer.getCodeLines());
    }

    @Override
    public void visit(Manager manager) {
        Log.d("TAG",  manager.name + ",產(chǎn)品數(shù)量: "+ manager.getProducts());
    }
}

  1. 報表類
/**
 * Created on 2019/4/12 14:45
 *
 * @author Scarf Gong
 */
public class Report {
    private List<Staff> mList = new ArrayList<>();

    public Report() {
        mList.add(new Manager("張經(jīng)理"));
        mList.add(new Engineer("Android工程師:小多"));
        mList.add(new Engineer("iOS工程師:小飛"));
        mList.add(new Engineer("java工程師:小熊"));
        mList.add(new Manager("李經(jīng)理"));
    }

    public void showReport(Visitor visitor) {
        for (Staff staff : mList) {
            staff.accept(visitor);
        }
    }
}
  1. 使用
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initData();
    }

    private void initData() {
        Report report = new Report();
        report.showReport(new CEOVisitor());
        Log.d("TAG", "----------分割線----------");
        report.showReport(new CTOVisitor());

    }
}
  1. 輸出結(jié)果
2019-04-12 15:02:47 D/TAG: 產(chǎn)品經(jīng)理: 張經(jīng)理,KPI:7,產(chǎn)品數(shù)量: 5
2019-04-12 15:02:47 D/TAG: Android工程師:小多,KPI: 5
2019-04-12 15:02:47 D/TAG: iOS工程師:小飛,KPI: 3
2019-04-12 15:02:47 D/TAG: java工程師:小熊,KPI: 1
2019-04-12 15:02:47 D/TAG: 產(chǎn)品經(jīng)理: 李經(jīng)理,KPI:7,產(chǎn)品數(shù)量: 8
2019-04-12 15:02:47 D/TAG: ----------分割線----------
2019-04-12 15:02:47 D/TAG: 張經(jīng)理,產(chǎn)品數(shù)量: 5
2019-04-12 15:02:47 D/TAG: Android工程師:小多,代碼數(shù)量: 63613
2019-04-12 15:02:47 D/TAG: iOS工程師:小飛,代碼數(shù)量: 44446
2019-04-12 15:02:47 D/TAG: java工程師:小熊,代碼數(shù)量: 81327
2019-04-12 15:02:47 D/TAG: 李經(jīng)理,產(chǎn)品數(shù)量: 8
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 3.9.1 模式意圖: 當我們已經(jīng)含有固定的數(shù)據(jù)結(jié)構(gòu),但需要頻繁的更改對數(shù)據(jù)操作的方式,如果將數(shù)據(jù)與行為放在一起,...
    su9257_海瀾閱讀 1,518評論 0 3
  • 定義:封裝某些作用于某種數(shù)據(jù)結(jié)構(gòu)中各元素的操作,它可以在不改變數(shù)據(jù)結(jié)構(gòu)的前提下定義作用于這些元素的新的操作。 ...
    haHahaHahaHaA閱讀 496評論 1 4
  • 很可笑對不對?去年的時候我也是這樣,在說過牽手之后就要放手,然后就再也沒有聯(lián)系過。作為一個女人,最希望的就是...
    鴦花舞閱讀 197評論 0 0
  • 這秋日艷陽 窗外樹木慵懶 飽滿的胃昏昏欲睡 午睡的孩子就要醒來 剖宮產(chǎn)的侄女今天出院 監(jiān)護室的孩子 讓人心酸 此刻...
    林有朽木閱讀 390評論 0 3
  • (1) 芬芳,是我開在頭上的花環(huán) 我把羞澀寫意在蕊間 盛放是我最熾烈的情感 在春風里,一任裙裾翩躚 (2) 綠意渲...
    改變自己369閱讀 461評論 10 15

友情鏈接更多精彩內(nèi)容